home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / termsorc.lha / Extras / Source / term-source.lha / termAux.c < prev    next >
C/C++ Source or Header  |  1995-09-28  |  90KB  |  4,823 lines

  1. /*
  2. **    termAux.c
  3. **
  4. **    Miscellaneous support routines
  5. **
  6. **    Copyright © 1990-1995 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* This variable stores the current state of the
  13.      * dialing menu items.
  14.      */
  15.  
  16. STATIC BYTE DialItemsAvailable = TRUE;
  17.  
  18.     /* Current timer state. */
  19.  
  20. STATIC BYTE TimerRunning = FALSE;
  21.  
  22. STATIC VOID
  23. StuffChar(VOID)
  24. {
  25.     __emit(0x16C0);    /* MOVE D0,(A3)+ */
  26. }
  27.  
  28.     /* SPrintf(STRPTR Buffer,STRPTR FormatString,...):
  29.      *
  30.      *    Just like sprintf(), but using the ROM routines.
  31.      */
  32.  
  33. VOID __stdargs
  34. SPrintf(STRPTR Buffer,STRPTR FormatString,...)
  35. {
  36.     va_list VarArgs;
  37.  
  38.     va_start(VarArgs,FormatString);
  39.     RawDoFmt(FormatString,VarArgs,(VOID (*)())StuffChar,Buffer);
  40.     va_end(VarArgs);
  41. }
  42.  
  43.     /* VSPrintf(STRPTR Buffer,STRPTR FormatString,va_list VarArgs):
  44.      *
  45.      *    Just like vsprintf(), but using the ROM routines.
  46.      */
  47.  
  48. VOID __regargs
  49. VSPrintf(STRPTR Buffer,STRPTR FormatString,va_list VarArgs)
  50. {
  51.     RawDoFmt(FormatString,VarArgs,(VOID (*)())StuffChar,Buffer);
  52. }
  53.  
  54.     /* Atol(STRPTR Buffer):
  55.      *
  56.      *    Convert ASCII representation to long word.
  57.      */
  58.  
  59. LONG __regargs
  60. Atol(STRPTR Buffer)
  61. {
  62.     LONG Result;
  63.  
  64.     StrToLong(Buffer,&Result);
  65.  
  66.     return(Result);
  67. }
  68.  
  69.     /* StripSpaces(STRPTR String):
  70.      *
  71.      *    Strip leading and trailing spaces from a string.
  72.      */
  73.  
  74. VOID __regargs
  75. StripSpaces(STRPTR String)
  76. {
  77.     if(String)
  78.     {
  79.         STRPTR    To = String;
  80.         WORD    Len;
  81.  
  82.         while(*String == ' ')
  83.             String++;
  84.  
  85.         if(Len = strlen(String))
  86.         {
  87.             while(Len > 0 && String[Len - 1] == ' ')
  88.                 Len--;
  89.  
  90.             while(Len--)
  91.                 *To++ = *String++;
  92.         }
  93.  
  94.         *To = 0;
  95.     }
  96. }
  97.  
  98.     /* ReplaceWindowInfo(struct WindowInfo *NewInfo):
  99.      *
  100.      *    Drop the window info into the right place.
  101.      */
  102.  
  103. VOID __regargs
  104. ReplaceWindowInfo(struct WindowInfo *NewInfo)
  105. {
  106.     WORD i;
  107.  
  108.     for(i = 0 ; i < WINDOW_COUNT ; i++)
  109.     {
  110.         if(WindowInfoTable[i] . ID == NewInfo -> ID)
  111.         {
  112.             CopyMem(NewInfo,&WindowInfoTable[i],sizeof(struct WindowInfo));
  113.  
  114.             break;
  115.         }
  116.     }
  117. }
  118.  
  119.     /* PutWindowInfo():
  120.      *
  121.      *    Store window size and position relative to
  122.      *    the main window.
  123.      */
  124.  
  125. VOID __regargs
  126. PutWindowInfo(UBYTE ID,LONG Left,LONG Top,LONG Width,LONG Height)
  127. {
  128.     struct WindowInfo    *Info;
  129.     WORD             i;
  130.     LONG             WindowLeft,
  131.                  WindowTop,
  132.                  WindowWidth,
  133.                  WindowHeight;
  134.     ULONG             IntuiLock;
  135.  
  136.     for(i = 0 ; i < WINDOW_COUNT ; i++)
  137.     {
  138.         if(WindowInfoTable[i] . ID == ID)
  139.         {
  140.             Info = &WindowInfoTable[i];
  141.  
  142.             break;
  143.         }
  144.     }
  145.  
  146.     IntuiLock = LockIBase(NULL);
  147.  
  148.     WindowLeft    = Window -> LeftEdge;
  149.     WindowTop    = Window -> TopEdge;
  150.     WindowWidth    = Window -> Width;
  151.     WindowHeight    = Window -> Height;
  152.  
  153.     UnlockIBase(IntuiLock);
  154.  
  155.     Forbid();
  156.  
  157.     Info -> WindowFlags = NULL;
  158.  
  159.     if(WindowWidth == Width && WindowLeft == Left)
  160.         Info -> WindowFlags |= WC_EXPANDWIDTH;
  161.     else
  162.     {
  163.         if(Left == WindowLeft + WindowWidth)
  164.             Info -> WindowFlags |= WC_ALIGNSIDE;
  165.  
  166.         if(WindowLeft == Left)
  167.             Info -> WindowFlags |= WC_ALIGNLEFT;
  168.  
  169.         if(WindowLeft + WindowWidth == Left + Width)
  170.             Info -> WindowFlags |= WC_ALIGNRIGHT;
  171.     }
  172.  
  173.     if(WindowHeight == Height && WindowTop == Top)
  174.         Info -> WindowFlags |= WC_EXPANDHEIGHT;
  175.     else
  176.     {
  177.         if(Top == WindowTop + WindowHeight)
  178.             Info -> WindowFlags |= WC_ALIGNBELOW;
  179.  
  180.         if(WindowTop == Top)
  181.             Info -> WindowFlags |= WC_ALIGNTOP;
  182.  
  183.         if(WindowTop + WindowHeight == Top + Height)
  184.             Info -> WindowFlags |= WC_ALIGNBOTTOM;
  185.     }
  186.  
  187.     Info -> Left    = Left;
  188.     Info -> Top    = Top;
  189.     Info -> Width    = Width;
  190.     Info -> Height    = Height;
  191.  
  192.     Permit();
  193. }
  194.  
  195.     /* GetWindowInfo():
  196.      *
  197.      *    Set the window size and position in relation to
  198.      *    the main window.
  199.      */
  200.  
  201. VOID __regargs
  202. GetWindowInfo(UBYTE ID,LONG *Left,LONG *Top,LONG *Width,LONG *Height,LONG DefWidth,LONG DefHeight)
  203. {
  204.     struct WindowInfo    *Info;
  205.     WORD             i;
  206.     LONG             WindowLeft,
  207.                  WindowTop,
  208.                  WindowWidth,
  209.                  WindowHeight;
  210.     ULONG             IntuiLock;
  211.  
  212.     if(Window)
  213.     {
  214.         if(DefWidth && DefWidth < Window -> Width / 2)
  215.             DefWidth = Window -> Width / 2;
  216.  
  217.         if(DefHeight && DefHeight < Window -> Height / 2)
  218.             DefHeight = Window -> Height / 2;
  219.     }
  220.  
  221.     for(i = 0 ; i < WINDOW_COUNT ; i++)
  222.     {
  223.         if(WindowInfoTable[i] . ID == ID)
  224.         {
  225.             Info = &WindowInfoTable[i];
  226.  
  227.             break;
  228.         }
  229.     }
  230.  
  231.     if(Info && ID == WINDOW_MAIN)
  232.     {
  233.         *Left    = Info -> Left;
  234.         *Top    = Info -> Top;
  235.  
  236.         return;
  237.     }
  238.  
  239.     if(Window)
  240.     {
  241.         IntuiLock = LockIBase(NULL);
  242.  
  243.         WindowLeft    = Window -> LeftEdge;
  244.         WindowTop    = Window -> TopEdge + Window -> BorderTop;
  245.         WindowWidth    = Window -> Width;
  246.         WindowHeight    = Window -> Height - Window -> BorderTop;
  247.  
  248.         UnlockIBase(IntuiLock);
  249.     }
  250.  
  251.     Forbid();
  252.  
  253.     if(*Width)
  254.     {
  255.         if(Info -> Width)
  256.             *Left = Info -> Left;
  257.         else
  258.             *Left = WindowLeft + (WindowWidth - *Width) / 2;
  259.     }
  260.     else
  261.     {
  262.         if(DefWidth && !Info -> Width)
  263.         {
  264.             *Width    = DefWidth;
  265.             *Left    = WindowLeft + (WindowWidth - *Width) / 2;
  266.         }
  267.         else
  268.         {
  269.             if(Info -> Width)
  270.             {
  271.                 *Width    = Info -> Width;
  272.                 *Left    = Info -> Left;
  273.             }
  274.             else
  275.             {
  276. /*                *Width    = WindowWidth / 2;*/
  277. /*                *Left    = WindowLeft + WindowWidth / 4;*/
  278.  
  279.                 *Width    = WindowWidth;
  280.                 *Left    = WindowLeft;
  281.             }
  282.         }
  283.     }
  284.  
  285.     if(*Height)
  286.     {
  287.         if(Info -> Height)
  288.             *Top = Info -> Top;
  289.         else
  290.             *Top = WindowTop + (WindowHeight - *Height) / 2;
  291.     }
  292.     else
  293.     {
  294.         if(DefHeight && !Info -> Height)
  295.         {
  296.             *Height    = DefHeight;
  297.             *Top    = WindowTop + (WindowHeight - *Height) / 2;
  298.         }
  299.         else
  300.         {
  301.             if(Info -> Height)
  302.             {
  303.                 *Height    = Info -> Height;
  304.                 *Top    = Info -> Top;
  305.             }
  306.             else
  307.             {
  308. /*                *Height    = WindowHeight / 2;*/
  309. /*                *Top    = WindowTop + WindowHeight / 4;*/
  310.  
  311.                 *Height    = WindowHeight;
  312.                 *Top    = WindowTop;
  313.             }
  314.         }
  315.     }
  316.  
  317.     if(Info -> WindowFlags & WC_ALIGNSIDE)
  318.         *Left = WindowLeft + WindowWidth;
  319.  
  320.     if(Info -> WindowFlags & WC_ALIGNBELOW)
  321.         *Top = WindowTop + WindowHeight;
  322.  
  323.     if(Info -> WindowFlags & WC_ALIGNLEFT)
  324.         *Left = WindowLeft;
  325.  
  326.     if(Info -> WindowFlags & WC_ALIGNTOP)
  327.         *Top = WindowTop;
  328.  
  329.     if(Info -> WindowFlags & WC_ALIGNRIGHT)
  330.         *Left = WindowLeft + WindowWidth - *Width;
  331.  
  332.     if(Info -> WindowFlags & WC_ALIGNBOTTOM)
  333.         *Top = WindowTop + WindowHeight - *Height;
  334.  
  335.     if(Info -> WindowFlags & WC_EXPANDWIDTH)
  336.         *Width = WindowWidth;
  337.  
  338.     if(Info -> WindowFlags & WC_EXPANDHEIGHT)
  339.         *Height = WindowHeight;
  340.  
  341.     Permit();
  342. }
  343.  
  344.     /* GetBitMapDepth(struct BitMap *BitMap):
  345.      *
  346.      *    Return the depth of a BitMap.
  347.      */
  348.  
  349. LONG __regargs
  350. GetBitMapDepth(struct BitMap *BitMap)
  351. {
  352.     LONG Depth;
  353.  
  354.     if(Kick30)
  355.         Depth = (LONG)GetBitMapAttr(BitMap,BMA_DEPTH);
  356.     else
  357.         Depth = BitMap -> Depth;
  358.  
  359.     if(Depth > 8)
  360.         Depth = 8;
  361.  
  362.     return(Depth);
  363. }
  364.  
  365.     /* GetDPI(ULONG Mode,ULONG *X_DPI,ULONG *Y_DPI):
  366.      *
  367.      *    Get screen DPI resolution values.
  368.      */
  369.  
  370. VOID __regargs
  371. GetDPI(ULONG Mode,ULONG *X_DPI,ULONG *Y_DPI)
  372. {
  373.     struct DisplayInfo DisplayInfo;
  374.  
  375.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode))
  376.     {
  377.         *X_DPI = (35 * 140) / DisplayInfo . PixelSpeed;
  378.         *Y_DPI = (*X_DPI * DisplayInfo . Resolution . x) / DisplayInfo . Resolution . y;
  379.     }
  380.     else
  381.         *X_DPI = *Y_DPI = 72;
  382. }
  383.  
  384.     /* AddProtection(STRPTR FileName,ULONG Mask):
  385.      *
  386.      *    Set bits in the protection mask of a file.
  387.      */
  388.  
  389. VOID __regargs
  390. AddProtection(STRPTR Name,ULONG Mask)
  391. {
  392.     struct FileInfoBlock *FileInfo;
  393.  
  394.     if(FileInfo = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_DONE))
  395.     {
  396.         BPTR FileLock;
  397.  
  398.         if(FileLock = Lock(Name,ACCESS_READ))
  399.         {
  400.             if(Examine(FileLock,FileInfo))
  401.             {
  402.                 UnLock(FileLock);
  403.  
  404.                 SetProtection(Name,FileInfo -> fib_Protection | Mask);
  405.             }
  406.             else
  407.                 UnLock(FileLock);
  408.         }
  409.  
  410.         FreeDosObject(DOS_FIB,FileInfo);
  411.     }
  412. }
  413.  
  414.     /* GetPubScreenName(struct Screen *Screen,STRPTR Name):
  415.      *
  416.      *    Get the name of a public screen.
  417.      */
  418.  
  419. BYTE __regargs
  420. GetPubScreenName(struct Screen *Screen,STRPTR Name)
  421. {
  422.     struct List        *PubScreenList;
  423.     struct PubScreenNode    *ScreenNode;
  424.  
  425.     PubScreenList = LockPubScreenList();
  426.  
  427.     for(ScreenNode = (struct PubScreenNode *)PubScreenList -> lh_Head ; ScreenNode -> psn_Node . ln_Succ ; ScreenNode = (struct PubScreenNode *)ScreenNode -> psn_Node . ln_Succ)
  428.     {
  429.         if(ScreenNode -> psn_Screen == Screen)
  430.         {
  431.             strcpy(Name,ScreenNode -> psn_Node . ln_Name);
  432.  
  433.             UnlockPubScreenList();
  434.  
  435.             return(TRUE);
  436.         }
  437.     }
  438.  
  439.     UnlockPubScreenList();
  440.  
  441.     return(FALSE);
  442. }
  443.  
  444.     /* InitSinglePort(struct MsgPort *Port):
  445.      *
  446.      *    Initialize a plain MsgPort (as created on the stack) for
  447.      *    usage. Don't try this at home, kids!
  448.      */
  449.  
  450. VOID __regargs
  451. InitSinglePort(struct MsgPort *Port)
  452. {
  453.     memset(Port,0,sizeof(struct MsgPort));
  454.  
  455.     Port -> mp_Flags    = PA_SIGNAL;
  456.     Port -> mp_SigBit    = SIGB_SINGLE;
  457.     Port -> mp_SigTask    = SysBase -> ThisTask;
  458.  
  459.     NewList(&Port -> mp_MsgList);
  460. }
  461.  
  462.     /* GoodStream(BPTR Stream):
  463.      *
  464.      *    Check to see whether the current input file
  465.      *    is an interactive stream.
  466.      */
  467.  
  468. BYTE __regargs
  469. GoodStream(BPTR Stream)
  470. {
  471.     if(!Stream)
  472.     {
  473.         struct Process *ThisProcess = (struct Process *)SysBase -> ThisTask;
  474.  
  475.         Stream = ThisProcess -> pr_CIS;
  476.     }
  477.  
  478.     if(Stream)
  479.     {
  480.         struct FileHandle *Handle = (struct FileHandle *)BADDR(Stream);
  481.  
  482.         if(Handle -> fh_Type)
  483.         {
  484.             if(IsInteractive(Stream))
  485.                 return(TRUE);
  486.         }
  487.     }
  488.  
  489.     return(FALSE);
  490. }
  491.  
  492.     /* GetProgramIcon():
  493.      *
  494.      *    Try to find the icon of the program.
  495.      */
  496.  
  497. struct DiskObject *
  498. GetProgramIcon()
  499. {
  500.     struct DiskObject *Icon = NULL;
  501.  
  502.         /* Run from Workbench? */
  503.  
  504.     if(WBenchMsg)
  505.     {
  506.             /* Sanity check. */
  507.  
  508.         if(WBenchMsg -> sm_ArgList)
  509.         {
  510.                 /* Yet another sanity check. */
  511.  
  512.             if(WBenchMsg -> sm_ArgList -> wa_Name)
  513.             {
  514.                     /* Try to find the icon in the current directory. */
  515.  
  516.                 if(Icon = GetDiskObjectNew(WBenchMsg -> sm_ArgList -> wa_Name))
  517.                 {
  518.                     if(Icon -> do_Type != WBTOOL)
  519.                     {
  520.                         FreeDiskObject(Icon);
  521.  
  522.                         Icon = NULL;
  523.                     }
  524.                 }
  525.  
  526.                 if(!Icon)
  527.                 {
  528.                     BPTR NewLock;
  529.  
  530.                         /* Move to the directory the
  531.                          * program was run from.
  532.                          */
  533.  
  534.                     if(NewLock = Lock("PROGDIR:",ACCESS_READ))
  535.                     {
  536.                         BPTR OldLock;
  537.  
  538.                         OldLock = CurrentDir(NewLock);
  539.  
  540.                             /* Try to fetch the icon, use the
  541.                              * default name if necessary.
  542.                              */
  543.  
  544.                         if(Icon = GetDiskObjectNew(WBenchMsg -> sm_ArgList -> wa_Name))
  545.                         {
  546.                             if(Icon -> do_Type != WBTOOL)
  547.                             {
  548.                                 FreeDiskObject(Icon);
  549.  
  550.                                 Icon = NULL;
  551.                             }
  552.                         }
  553.  
  554.                         if(!Icon)
  555.                         {
  556.                             if(Icon = GetDiskObjectNew("term"))
  557.                             {
  558.                                 if(Icon -> do_Type != WBTOOL)
  559.                                 {
  560.                                     FreeDiskObject(Icon);
  561.  
  562.                                     Icon = NULL;
  563.                                 }
  564.                             }
  565.                         }
  566.  
  567.                         CurrentDir(OldLock);
  568.  
  569.                         UnLock(NewLock);
  570.                     }
  571.                 }
  572.             }
  573.         }
  574.     }
  575.  
  576.         /* Still no success. */
  577.  
  578.     if(!Icon)
  579.     {
  580.             /* Use the default names. */
  581.  
  582.         if(Icon = GetDiskObjectNew("term"))
  583.         {
  584.             if(Icon -> do_Type != WBTOOL)
  585.             {
  586.                 FreeDiskObject(Icon);
  587.  
  588.                 Icon = NULL;
  589.             }
  590.         }
  591.  
  592.         if(!Icon)
  593.         {
  594.             if(Icon = GetDiskObjectNew("PROGDIR:term"))
  595.             {
  596.                 if(Icon -> do_Type != WBTOOL)
  597.                 {
  598.                     FreeDiskObject(Icon);
  599.  
  600.                     Icon = NULL;
  601.                 }
  602.             }
  603.         }
  604.     }
  605.  
  606.     return(Icon);
  607. }
  608.  
  609.     /* GetPenIndex(LONG Pen):
  610.      *
  611.      *    Get the table index corresponding to an on-screen
  612.      *    text rendering pen.
  613.      */
  614.  
  615. LONG __regargs
  616. GetPenIndex(LONG Pen)
  617. {
  618.     LONG i;
  619.  
  620.     for(i = 0 ; i < 16 ; i++)
  621.     {
  622.         if(MappedPens[0][i] == Pen)
  623.             return(i);
  624.     }
  625. }
  626.  
  627.     /* GetScreenWidth(struct Window *Window):
  628.      *
  629.      *    Query the current screen width.
  630.      */
  631.  
  632. LONG __regargs
  633. GetScreenWidth(struct Window *Window)
  634. {
  635.     if(Window)
  636.     {
  637.         if(Window -> Width > ScreenWidth || Window -> LeftEdge < -Window -> WScreen -> LeftEdge || Window -> LeftEdge + Window -> WScreen -> LeftEdge + Window -> Width > ScreenWidth)
  638.             return(ScreenWidth);
  639.         else
  640.             return(Window -> Width - (Window -> BorderLeft + Window -> BorderRight));
  641.     }
  642.     else
  643.         return(ScreenWidth);
  644. }
  645.  
  646.     /* GetScreenHeight(struct Window *Window):
  647.      *
  648.      *    Query the current screen height.
  649.      */
  650.  
  651. LONG __regargs
  652. GetScreenHeight(struct Window *Window)
  653. {
  654.     if(Window)
  655.     {
  656.         if(Window -> Height > ScreenHeight || Window -> TopEdge < -Window -> WScreen -> TopEdge || Window -> TopEdge + Window -> WScreen -> TopEdge + Window -> Height > ScreenHeight)
  657.             return(ScreenHeight);
  658.         else
  659.             return(Window -> Height - (Window -> BorderTop + Window -> BorderBottom));
  660.     }
  661.     else
  662.         return(ScreenHeight);
  663. }
  664.  
  665.     /* GetLeft(struct Screen *Screen):
  666.      *
  667.      *    Get the screen left edge.
  668.      */
  669.  
  670. STATIC LONG __regargs
  671. GetLeft(struct Screen *Screen)
  672. {
  673.     if(Screen -> LeftEdge >= 0)
  674.         return(0);
  675.     else
  676.         return(-Screen -> LeftEdge);
  677. }
  678.  
  679.     /* GetScreenLeft(struct Window *Window):
  680.      *
  681.      *    Query the current screen left edge.
  682.      */
  683.  
  684. LONG __regargs
  685. GetScreenLeft(struct Window *Window)
  686. {
  687.     if(Window)
  688.     {
  689.         if(Window -> Width > ScreenWidth || Window -> LeftEdge < -Window -> WScreen -> LeftEdge || Window -> LeftEdge + Window -> WScreen -> LeftEdge + Window -> Width > ScreenWidth)
  690.             return(GetLeft(Window -> WScreen));
  691.         else
  692.             return(Window -> LeftEdge + Window -> BorderLeft);
  693.     }
  694.     else
  695.         return(GetLeft(DefaultPubScreen ? DefaultPubScreen : SharedScreen));
  696. }
  697.  
  698.     /* GetTop(struct Screen *Screen):
  699.      *
  700.      *    Get the screen top edge.
  701.      */
  702.  
  703. STATIC LONG __regargs
  704. GetTop(struct Screen *Screen)
  705. {
  706.     if(Screen -> TopEdge >= 0)
  707.         return(0);
  708.     else
  709.         return(-Screen -> TopEdge);
  710. }
  711.  
  712.     /* GetScreenTop(struct Window *Window):
  713.      *
  714.      *    Query the current screen top edge.
  715.      */
  716.  
  717. LONG __regargs
  718. GetScreenTop(struct Window *Window)
  719. {
  720.     if(Window)
  721.     {
  722.         if(Window -> Height > ScreenHeight || Window -> TopEdge < -Window -> WScreen -> TopEdge || Window -> TopEdge + Window -> WScreen -> TopEdge + Window -> Height > ScreenHeight)
  723.             return(GetTop(Window -> WScreen));
  724.         else
  725.             return(Window -> TopEdge + Window -> BorderTop);
  726.     }
  727.     else
  728.         return(GetTop(DefaultPubScreen ? DefaultPubScreen : SharedScreen));
  729. }
  730.  
  731.     /* OldGetAPen(struct RastPort *RPort):
  732.      *
  733.      *    Query the current primary rendering colour (old style).
  734.      */
  735.  
  736. ULONG
  737. OldGetAPen(struct RastPort *RPort)
  738. {
  739.     return((ULONG)RPort -> FgPen);
  740. }
  741.  
  742.     /* OldGetBPen(struct RastPort *RPort):
  743.      *
  744.      *    Query the current seconary rendering colour (old style).
  745.      */
  746.  
  747. ULONG
  748. OldGetBPen(struct RastPort *RPort)
  749. {
  750.     return((ULONG)RPort -> BgPen);
  751. }
  752.  
  753.     /* OldGetDrMd(struct RastPort *RPort):
  754.      *
  755.      *    Query the current drawing mode (old style).
  756.      */
  757.  
  758. ULONG
  759. OldGetDrMd(struct RastPort *RPort)
  760. {
  761.     return((ULONG)RPort -> DrawMode);
  762. }
  763.  
  764.     /* OldSetWrMsk(struct RastPort *RPort,ULONG Mask):
  765.      *
  766.      *    Set the rendering plane mask (old style).
  767.      */
  768.  
  769. ULONG
  770. OldSetWrMsk(struct RastPort *RPort,ULONG Mask)
  771. {
  772.     if(UseMasking)
  773.         RPort -> Mask = Mask;
  774.  
  775.     return((ULONG)1);
  776. }
  777.  
  778.     /* NewGetAPen(struct RastPort *RPort):
  779.      *
  780.      *    Query the current primary rendering colour (new style).
  781.      */
  782.  
  783. ULONG
  784. NewGetAPen(struct RastPort *RPort)
  785. {
  786.     return(GetAPen(RPort));
  787. }
  788.  
  789.     /* NewGetBPen(struct RastPort *RPort):
  790.      *
  791.      *    Query the current seconary rendering colour (new style).
  792.      */
  793.  
  794. ULONG
  795. NewGetBPen(struct RastPort *RPort)
  796. {
  797.     return(GetBPen(RPort));
  798. }
  799.  
  800.     /* NewGetDrMd(struct RastPort *RPort):
  801.      *
  802.      *    Query the current drawing mode (new style).
  803.      */
  804.  
  805. ULONG
  806. NewGetDrMd(struct RastPort *RPort)
  807. {
  808.     return(GetDrMd(RPort));
  809. }
  810.  
  811.     /* NewSetWrMsk(struct RastPort *RPort,ULONG Mask):
  812.      *
  813.      *    Set the rendering plane mask (new style).
  814.      */
  815.  
  816. ULONG
  817. NewSetWrMsk(struct RastPort *RPort,ULONG Mask)
  818. {
  819.     if(UseMasking)
  820.         return(SetWriteMask(RPort,Mask));
  821.     else
  822.         return((ULONG)1);
  823. }
  824.  
  825.     /* SetWait(struct Window *Window):
  826.      *
  827.      *    Set the busy wait mouse pointer.
  828.      */
  829.  
  830. VOID __regargs
  831. SetWait(struct Window *Window)
  832. {
  833.     if(Kick30)
  834.     {
  835.         SetWindowPointer(Window,
  836.             WA_BusyPointer,        TRUE,
  837.             WA_PointerDelay,    TRUE,
  838.         TAG_DONE);
  839.     }
  840.     else
  841.         SetPointer(Window,Stopwatch,16,16,-6,0);
  842. }
  843.  
  844.     /* ClrWait(struct Window *Window):
  845.      *
  846.      *    Remove the busy wait mouse pointer.
  847.      */
  848.  
  849. VOID __regargs
  850. ClrWait(struct Window *Window)
  851. {
  852.     if(Kick30)
  853.         SetWindowPointer(Window,TAG_DONE);
  854.     else
  855.         ClearPointer(Window);
  856. }
  857.  
  858.     /* GetModeName(ULONG Mode):
  859.      *
  860.      *    Get the name of a display mode.
  861.      */
  862.  
  863. STRPTR __regargs
  864. GetModeName(ULONG Mode)
  865. {
  866.     STATIC UBYTE __far    Buffer[DISPLAYNAMELEN + 1];
  867.     struct NameInfo        NameInfo;
  868.  
  869.     if(GetDisplayInfoData(NULL,(APTR)&NameInfo,sizeof(struct NameInfo),DTAG_NAME,Mode))
  870.         strcpy(Buffer,NameInfo . Name);
  871.     else
  872.     {
  873.         struct DimensionInfo DimensionInfo;
  874.  
  875.         if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,Mode))
  876.         {
  877.             STRPTR MonitorName;
  878.  
  879.             switch(Mode & MONITOR_ID_MASK)
  880.             {
  881.                 case NTSC_MONITOR_ID:
  882.  
  883.                     MonitorName = "NTSC:";
  884.                     break;
  885.  
  886.                 case PAL_MONITOR_ID:
  887.  
  888.                     MonitorName = "PAL:";
  889.                     break;
  890.  
  891.                 case VGA_MONITOR_ID:
  892.  
  893.                     MonitorName = "VGA:";
  894.                     break;
  895.  
  896.                 case A2024_MONITOR_ID:
  897.  
  898.                     MonitorName = "A2024:";
  899.                     break;
  900.  
  901.                 default:
  902.  
  903.                     MonitorName = "";
  904.                     break;
  905.             }
  906.  
  907.             SPrintf(Buffer,"%s%ldx%ld",MonitorName,DimensionInfo . TxtOScan . MaxX - DimensionInfo . TxtOScan . MinX + 1,DimensionInfo . TxtOScan . MaxY - DimensionInfo . TxtOScan . MinY + 1);
  908.         }
  909.         else
  910.             strcpy(Buffer,LocaleString(MSG_SCREENPANEL_UNKNOWN_TXT));
  911.     }
  912.  
  913.     return(Buffer);
  914. }
  915.  
  916.     /* ModeOkay(ULONG ID):
  917.      *
  918.      *    Checks whether a display mode ID will do for deep
  919.      *    screen bitmaps.
  920.      */
  921.  
  922. BYTE __regargs
  923. ModeOkay(ULONG ID)
  924. {
  925.     struct DimensionInfo DimensionInfo;
  926.  
  927.     if(GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,ID))
  928.     {
  929.         if(DimensionInfo . MaxDepth >= 4)
  930.             return(TRUE);
  931.     }
  932.  
  933.     return(FALSE);
  934. }
  935.  
  936.     /* SetClipMenu(BYTE Mode):
  937.      *
  938.      *    Enable/disable the copy/clear selection menu items.
  939.      */
  940.  
  941. VOID __regargs
  942. SetClipMenu(BYTE Mode)
  943. {
  944.     if(Mode && RasterEnabled)
  945.     {
  946.         OnItem(MEN_COPY);
  947.         OnItem(MEN_CLEAR);
  948.     }
  949.     else
  950.     {
  951.         OffItem(MEN_COPY);
  952.         OffItem(MEN_CLEAR);
  953.     }
  954. }
  955.  
  956.     /* SetRedialMenu():
  957.      *
  958.      *    Make the `redial' menu item available or make it
  959.      *    unavailable.
  960.      */
  961.  
  962. VOID
  963. SetRedialMenu()
  964. {
  965.     BYTE Mode;
  966.  
  967.     if(DialList)
  968.     {
  969.         if(DialList -> lh_Head -> ln_Succ)
  970.             Mode = TRUE;
  971.         else
  972.             Mode = FALSE;
  973.     }
  974.     else
  975.         Mode = FALSE;
  976.  
  977.     if(Mode && (DialItemsAvailable || Config -> MiscConfig -> ProtectiveMode))
  978.         OnItem(MEN_REDIAL);
  979.     else
  980.         OffItem(MEN_REDIAL);
  981. }
  982.  
  983.     /* SetDialMenu(BYTE Mode):
  984.      *
  985.      *    Block or enable the dialing menu.
  986.      */
  987.  
  988. VOID __regargs
  989. SetDialMenu(BYTE Mode)
  990. {
  991.     if(Window && Menu)
  992.     {
  993.         if(Mode || Config -> MiscConfig -> ProtectiveMode)
  994.         {
  995.             if(DialList)
  996.             {
  997.                 if(DialList -> lh_Head -> ln_Succ)
  998.                     OnItem(MEN_REDIAL);
  999.                 else
  1000.                     OffItem(MEN_REDIAL);
  1001.             }
  1002.             else
  1003.                 OffItem(MEN_REDIAL);
  1004.  
  1005.             OnItem(MEN_DIAL_NUMBER);
  1006.  
  1007.             if(FirstDialMenu != -1)
  1008.                 OnItem(MEN_EXTRA_DIAL);
  1009.         }
  1010.         else
  1011.         {
  1012.             OffItem(MEN_REDIAL);
  1013.             OffItem(MEN_DIAL_NUMBER);
  1014.  
  1015.             if(FirstDialMenu != -1)
  1016.                 OffItem(MEN_EXTRA_DIAL);
  1017.         }
  1018.  
  1019.         DialItemsAvailable = Mode;
  1020.     }
  1021. }
  1022.  
  1023.     /* SetTransferMenu(BYTE Mode):
  1024.      *
  1025.      *    Block or enable the transfer menu.
  1026.      */
  1027.  
  1028. VOID __regargs
  1029. SetTransferMenu(BYTE Mode)
  1030. {
  1031.     if(Window && Menu)
  1032.     {
  1033.         BOOLEAN    ValidDefault,
  1034.             ValidASCIIDownload,
  1035.             ValidASCIIUpload,
  1036.             ValidTextDownload,
  1037.             ValidTextUpload,
  1038.             ValidBinaryDownload,
  1039.             ValidBinaryUpload;
  1040.  
  1041.         if(!Config -> TransferConfig -> DefaultLibrary[0] || !Mode || (!XProtocolBase && Config -> TransferConfig -> DefaultType == XFER_XPR))
  1042.             ValidDefault = FALSE;
  1043.         else
  1044.             ValidDefault = TRUE;
  1045.  
  1046.         switch(Config -> TransferConfig -> ASCIIUploadType)
  1047.         {
  1048.             case XFER_INTERNAL:
  1049.  
  1050.                 ValidASCIIUpload = TRUE;
  1051.                 break;
  1052.  
  1053.             case XFER_DEFAULT:
  1054.  
  1055.                 ValidASCIIUpload = ValidDefault;
  1056.                 break;
  1057.  
  1058.             case XFER_XPR:
  1059.             case XFER_EXTERNALPROGRAM:
  1060.  
  1061.                 ValidASCIIUpload = Config -> TransferConfig -> ASCIIUploadLibrary[0];
  1062.                 break;
  1063.         }
  1064.  
  1065.         switch(Config -> TransferConfig -> ASCIIDownloadType)
  1066.         {
  1067.             case XFER_INTERNAL:
  1068.  
  1069.                 ValidASCIIDownload = TRUE;
  1070.                 break;
  1071.  
  1072.             case XFER_DEFAULT:
  1073.  
  1074.                 ValidASCIIDownload = ValidDefault;
  1075.                 break;
  1076.  
  1077.             case XFER_XPR:
  1078.             case XFER_EXTERNALPROGRAM:
  1079.  
  1080.                 ValidASCIIDownload = Config -> TransferConfig -> ASCIIDownloadLibrary[0];
  1081.                 break;
  1082.         }
  1083.  
  1084.  
  1085.         switch(Config -> TransferConfig -> TextUploadType)
  1086.         {
  1087.             case XFER_DEFAULT:
  1088.  
  1089.                 ValidTextUpload = ValidDefault;
  1090.                 break;
  1091.  
  1092.             case XFER_XPR:
  1093.             case XFER_EXTERNALPROGRAM:
  1094.  
  1095.                 ValidTextUpload = Config -> TransferConfig -> TextUploadLibrary[0];
  1096.                 break;
  1097.         }
  1098.  
  1099.         switch(Config -> TransferConfig -> TextDownloadType)
  1100.         {
  1101.             case XFER_DEFAULT:
  1102.  
  1103.                 ValidTextDownload = ValidDefault;
  1104.                 break;
  1105.  
  1106.             case XFER_XPR:
  1107.             case XFER_EXTERNALPROGRAM:
  1108.  
  1109.                 ValidTextDownload = Config -> TransferConfig -> TextDownloadLibrary[0];
  1110.                 break;
  1111.         }
  1112.  
  1113.         switch(Config -> TransferConfig -> BinaryUploadType)
  1114.         {
  1115.             case XFER_DEFAULT:
  1116.  
  1117.                 ValidBinaryUpload = ValidDefault;
  1118.                 break;
  1119.  
  1120.             case XFER_XPR:
  1121.             case XFER_EXTERNALPROGRAM:
  1122.  
  1123.                 ValidBinaryUpload = Config -> TransferConfig -> BinaryUploadLibrary[0];
  1124.                 break;
  1125.         }
  1126.  
  1127.         switch(Config -> TransferConfig -> BinaryDownloadType)
  1128.         {
  1129.             case XFER_DEFAULT:
  1130.  
  1131.                 ValidBinaryDownload = ValidDefault;
  1132.                 break;
  1133.  
  1134.             case XFER_XPR:
  1135.             case XFER_EXTERNALPROGRAM:
  1136.  
  1137.                 ValidBinaryDownload = Config -> TransferConfig -> BinaryDownloadLibrary[0];
  1138.                 break;
  1139.         }
  1140.  
  1141.         if(ValidASCIIUpload)
  1142.             OnItem(MEN_UPLOAD_ASCII);
  1143.         else
  1144.             OffItem(MEN_UPLOAD_ASCII);
  1145.  
  1146.         if(ValidASCIIDownload)
  1147.             OnItem(MEN_DOWNLOAD_ASCII);
  1148.         else
  1149.             OffItem(MEN_DOWNLOAD_ASCII);
  1150.  
  1151.         if(ValidTextUpload)
  1152.         {
  1153.             OnItem(MEN_UPLOAD_TEXT);
  1154.             OnItem(MEN_EDIT_AND_UPLOAD_TEXT);
  1155.         }
  1156.         else
  1157.         {
  1158.             OffItem(MEN_UPLOAD_TEXT);
  1159.             OffItem(MEN_EDIT_AND_UPLOAD_TEXT);
  1160.         }
  1161.  
  1162.         if(ValidTextDownload)
  1163.             OnItem(MEN_DOWNLOAD_TEXT);
  1164.         else
  1165.             OffItem(MEN_DOWNLOAD_TEXT);
  1166.  
  1167.         if(ValidBinaryUpload)
  1168.             OnItem(MEN_UPLOAD_BINARY);
  1169.         else
  1170.             OffItem(MEN_UPLOAD_BINARY);
  1171.  
  1172.         if(ValidBinaryDownload)
  1173.             OnItem(MEN_DOWNLOAD_BINARY);
  1174.         else
  1175.             OffItem(MEN_DOWNLOAD_BINARY);
  1176.  
  1177.         if(ValidDefault)
  1178.             OnItem(MEN_TRANSFER);
  1179.         else
  1180.             OffItem(MEN_TRANSFER);
  1181.     }
  1182. }
  1183.  
  1184.     /* SetRasterMenu(BYTE Mode):
  1185.      *
  1186.      *    Block or enable the menu entries associated with
  1187.      *    functions to access the screen raster.
  1188.      */
  1189.  
  1190. VOID __regargs
  1191. SetRasterMenu(BYTE Mode)
  1192. {
  1193.     if(Window && Menu)
  1194.     {
  1195.         if(Mode)
  1196.         {
  1197.             OnItem(MEN_SAVE_AS_TEXT);
  1198.             OnItem(MEN_PRINT_SCREEN);
  1199.         }
  1200.         else
  1201.         {
  1202.             OffItem(MEN_SAVE_AS_TEXT);
  1203.             OffItem(MEN_PRINT_SCREEN);
  1204.         }
  1205.     }
  1206. }
  1207.  
  1208.     /* PickFont(struct Window *Window,STRPTR Name,WORD *Points,BYTE MonoSpaced):
  1209.      *
  1210.      *    Pick a font using asl.library
  1211.      */
  1212.  
  1213. BYTE __regargs
  1214. PickFont(struct Window *Window,STRPTR Name,WORD *Points,BYTE MonoSpaced)
  1215. {
  1216.     struct FontRequester    *Requester;
  1217.     struct TagItem         DimensionTags[5];
  1218.     BYTE             Result = FALSE;
  1219.  
  1220.     if(Requester = (struct FontRequester *)AllocAslRequestTags(ASL_FontRequest,
  1221.         ASLFO_Window,        Window,
  1222.         ASLFO_InitialName,    Name,
  1223.         ASLFO_InitialSize,    *Points,
  1224.         ASLFO_InitialFrontPen,    DrawInfo -> dri_Pens[TEXTPEN],
  1225.         ASLFO_InitialBackPen,    DrawInfo -> dri_Pens[BACKGROUNDPEN],
  1226.         ASLFO_PrivateIDCMP,    TRUE,
  1227.  
  1228.         ASL_FuncFlags,        MonoSpaced ? (FONF_NEWIDCMP|FONF_FIXEDWIDTH) : FONF_NEWIDCMP,
  1229.     TAG_MORE,GetDimensionTags(NULL,DimensionTags)))
  1230.     {
  1231.         LT_LockWindow(Window);
  1232.  
  1233.         if(AslRequest(Requester,NULL))
  1234.         {
  1235.             PutDimensionTags(NULL,Requester -> fo_LeftEdge,Requester -> fo_TopEdge,Requester -> fo_Width,Requester -> fo_Height);
  1236.  
  1237.             strcpy(Name,Requester -> fo_Attr . ta_Name);
  1238.  
  1239.             *Points = Requester -> fo_Attr . ta_YSize;
  1240.  
  1241.             Result = TRUE;
  1242.         }
  1243.  
  1244.         LT_UnlockWindow(Window);
  1245.  
  1246.         FreeAslRequest(Requester);
  1247.     }
  1248.  
  1249.     return(Result);
  1250. }
  1251.  
  1252.     /* ExtractString():
  1253.      *
  1254.      *    Extracts a string from a list separated by `|' characters.
  1255.      */
  1256.  
  1257. STRPTR __regargs
  1258. ExtractString(STRPTR String,STRPTR Destination,BYTE ReturnEnd)
  1259. {
  1260.     STRPTR OldString;
  1261.  
  1262.     if(ReturnEnd)
  1263.         OldString = NULL;
  1264.     else
  1265.         OldString = String;
  1266.  
  1267.     while(*String)
  1268.     {
  1269.         if(*String == '|')
  1270.         {
  1271.             *Destination = 0;
  1272.  
  1273.             String++;
  1274.  
  1275.             if(*String)
  1276.                 return(String);
  1277.             else
  1278.                 return(OldString);
  1279.         }
  1280.         else
  1281.             *Destination++ = *String++;
  1282.     }
  1283.  
  1284.     *Destination = 0;
  1285.  
  1286.     return(OldString);
  1287. }
  1288.  
  1289.     /* GetListSize(struct List *List):
  1290.      *
  1291.      *    Determine the number of entries in a list.
  1292.      */
  1293.  
  1294. LONG __regargs
  1295. GetListSize(struct List *List)
  1296. {
  1297.     struct Node    *Node    = List -> lh_Head;
  1298.     LONG         i    = 0;
  1299.  
  1300.     while(Node -> ln_Succ)
  1301.     {
  1302.         i++;
  1303.  
  1304.         Node = Node -> ln_Succ;
  1305.     }
  1306.  
  1307.     return(i);
  1308. }
  1309.  
  1310.     /* GetListNode(LONG Offset,struct List *List):
  1311.      *
  1312.      *    Return the n-th Node entry in a standard exec list.
  1313.      */
  1314.  
  1315. struct Node * __regargs
  1316. GetListNode(LONG Offset,struct List *List)
  1317. {
  1318.     struct Node    *Node;
  1319.     LONG         i;
  1320.  
  1321.     Node = List -> lh_Head;
  1322.  
  1323.     for(i = 0 ; i < Offset ; i++)
  1324.     {
  1325.         if(!Node -> ln_Succ -> ln_Succ)
  1326.             return(NULL);
  1327.  
  1328.         Node = Node -> ln_Succ;
  1329.     }
  1330.  
  1331.     return(Node);
  1332. }
  1333.  
  1334.     /* CreateNode(STRPTR Name):
  1335.      *
  1336.      *    Put a name string into a list node.
  1337.      */
  1338.  
  1339. struct Node * __regargs
  1340. CreateNode(STRPTR Name)
  1341. {
  1342.     struct Node *Node;
  1343.  
  1344.     if(Node = (struct Node *)AllocVecPooled(sizeof(struct Node) + strlen(Name) + 1,MEMF_ANY | MEMF_PUBLIC))
  1345.     {
  1346.         Node -> ln_Name = (STRPTR)(Node + 1);
  1347.  
  1348.         strcpy(Node -> ln_Name,Name);
  1349.     }
  1350.  
  1351.     return(Node);
  1352. }
  1353.  
  1354.     /* FreeNode(struct Node *Node):
  1355.      *
  1356.      *    Remove and deallocate a node.
  1357.      */
  1358.  
  1359. VOID __regargs
  1360. FreeNode(struct Node *Node)
  1361. {
  1362.     Remove(Node);
  1363.  
  1364.     FreeVecPooled(Node);
  1365. }
  1366.  
  1367.     /* FreeList(struct List *List):
  1368.      *
  1369.      *    Remove all nodes from the list
  1370.      *    and free them on the way.
  1371.      */
  1372.  
  1373. VOID __regargs
  1374. FreeList(struct List *List)
  1375. {
  1376.     struct Node *Node;
  1377.  
  1378.     while(Node = RemHead(List))
  1379.         FreeVecPooled(Node);
  1380. }
  1381.  
  1382.     /* GetNodeOffset(struct Node *Node,struct List *List):
  1383.      *
  1384.      *    Scan a list for a certain node and return
  1385.      *    its position.
  1386.      */
  1387.  
  1388. LONG __regargs
  1389. GetNodeOffset(struct Node *Node,struct List *List)
  1390. {
  1391.     struct Node    *ListNode;
  1392.     LONG         Offset = 0;
  1393.  
  1394.     ListNode = List -> lh_Head;
  1395.  
  1396.     while(ListNode -> ln_Succ)
  1397.     {
  1398.         if(Node == ListNode)
  1399.             return(Offset);
  1400.         else
  1401.         {
  1402.             Offset++;
  1403.  
  1404.             ListNode = ListNode -> ln_Succ;
  1405.         }
  1406.     }
  1407.  
  1408.     return(~0);
  1409. }
  1410.  
  1411.     /* MoveList(struct List *From,struct List *To):
  1412.      *
  1413.      *    Move the contents of a list to a different list.
  1414.      */
  1415.  
  1416. VOID __regargs
  1417. MoveList(struct List *From,struct List *To)
  1418. {
  1419.     struct Node *Node;
  1420.  
  1421.     while(Node = RemHead(From))
  1422.         AddTail(To,Node);
  1423. }
  1424.  
  1425.     /* LogAction(STRPTR String,...):
  1426.      *
  1427.      *    Write an action to the default log file.
  1428.      */
  1429.  
  1430. VOID __stdargs
  1431. LogAction(STRPTR String,...)
  1432. {
  1433.     if(Config -> CaptureConfig -> LogActions && Config -> CaptureConfig -> LogFileName[0])
  1434.     {
  1435.         UBYTE    DummyBuffer[512];
  1436.         BPTR    File;
  1437.  
  1438.         va_list    VarArgs;
  1439.  
  1440.             /* Build a valid string. */
  1441.  
  1442.         va_start(VarArgs,String);
  1443.         VSPrintf(DummyBuffer,String,VarArgs);
  1444.         va_end(VarArgs);
  1445.  
  1446.             /* Does the log file already exist? */
  1447.  
  1448.         if(GetFileSize(Config -> CaptureConfig -> LogFileName))
  1449.         {
  1450.                 /* It does, let's append the data. */
  1451.  
  1452.             if(File = Open(Config -> CaptureConfig -> LogFileName,MODE_READWRITE))
  1453.             {
  1454.                 if(Seek(File,0,OFFSET_END) == -1)
  1455.                 {
  1456.                     Close(File);
  1457.  
  1458.                     File = NULL;
  1459.                 }
  1460.             }
  1461.         }
  1462.         else
  1463.         {
  1464.                 /* Create a new file. */
  1465.  
  1466.             if(File = Open(Config -> CaptureConfig -> LogFileName,MODE_NEWFILE))
  1467.                 FPrintf(File,LocaleString(MSG_TERMAUX_DATE_TIME_ACTION_TXT));
  1468.         }
  1469.  
  1470.             /* The file is open, build the date/time string and
  1471.              * write the log action.
  1472.              */
  1473.  
  1474.         if(File)
  1475.         {
  1476.             UBYTE        DateBuffer[40],
  1477.                     TimeBuffer[40];
  1478.             struct DateTime    DateTime;
  1479.  
  1480.             DateStamp(&DateTime . dat_Stamp);
  1481.  
  1482.             DateTime . dat_Format    = FORMAT_DOS;
  1483.             DateTime . dat_Flags    = NULL;
  1484.             DateTime . dat_StrDay    = NULL;
  1485.             DateTime . dat_StrDate    = DateBuffer;
  1486.             DateTime . dat_StrTime    = TimeBuffer;
  1487.  
  1488.             if(DateToStr(&DateTime))
  1489.             {
  1490.                 StripSpaces(TimeBuffer);
  1491.  
  1492.                 FPrintf(File,"%-9s %8s %s\n",DateBuffer,TimeBuffer,DummyBuffer);
  1493.             }
  1494.  
  1495.                 /* Done! */
  1496.  
  1497.             Close(File);
  1498.         }
  1499.     }
  1500. }
  1501.  
  1502.     /* FlushMsg(struct Window *Window):
  1503.      *
  1504.      *    Cancel all pending messages of a window.
  1505.      */
  1506.  
  1507. VOID __regargs
  1508. FlushMsg(struct Window *Window)
  1509. {
  1510.     struct IntuiMessage *Massage;
  1511.  
  1512.     while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
  1513.         ReplyMsg(&Massage -> ExecMessage);
  1514. }
  1515.  
  1516.     /* GetString(STRPTR Prompt,STRPTR Buffer):
  1517.      *
  1518.      *    Get a string from the user, very much the same as xpr_gets,
  1519.      *    but also including the `Load File' gadget.
  1520.      */
  1521.  
  1522. BYTE __regargs
  1523. GetString(BYTE LoadGadget,BYTE Password,WORD MaxChars,STRPTR Prompt,STRPTR Buffer)
  1524. {
  1525.     enum    {    GAD_OK=1,GAD_CANCEL,GAD_STRING };
  1526.  
  1527.     struct LayoutHandle    *Handle;
  1528.     BYTE             Success = FALSE;
  1529.     UBYTE             LocalBuffer[256];
  1530.  
  1531.     if(!MaxChars)
  1532.         MaxChars = 255;
  1533.  
  1534.     if(MaxChars > 255)
  1535.     {
  1536.         CopyMem(Buffer,LocalBuffer,255);
  1537.  
  1538.         LocalBuffer[255] = 0;
  1539.  
  1540.         MaxChars = 255;
  1541.     }
  1542.     else
  1543.         strcpy(LocalBuffer,Buffer);
  1544.  
  1545.     if(!Prompt)
  1546.         Prompt = LocaleString(MSG_TERMXPR_INPUT_REQUIRED_TXT);
  1547.  
  1548.     if(Handle = LT_CreateHandleTags(Window -> WScreen,
  1549.         LH_LocaleHook,    &LocaleHook,
  1550.     TAG_DONE))
  1551.     {
  1552.         struct Window *PanelWindow;
  1553.  
  1554.         LT_New(Handle,
  1555.             LA_Type,    VERTICAL_KIND,
  1556.         TAG_DONE);
  1557.         {
  1558.             LT_New(Handle,
  1559.                 LA_Type,    VERTICAL_KIND,
  1560.                 LA_LabelText,    Prompt,
  1561.             TAG_DONE);
  1562.             {
  1563.                 if(Password)
  1564.                 {
  1565.                     LT_New(Handle,
  1566.                         LA_Type,    PASSWORD_KIND,
  1567.                         LA_STRPTR,    LocalBuffer,
  1568.                         LA_ID,        GAD_STRING,
  1569.                         LA_Chars,    40,
  1570.                         GTST_MaxChars,    MaxChars,
  1571.                     TAG_DONE);
  1572.                 }
  1573.                 else
  1574.                 {
  1575.                     LT_New(Handle,
  1576.                         LA_Type,    STRING_KIND,
  1577.                         LA_STRPTR,    LocalBuffer,
  1578.                         LA_ID,        GAD_STRING,
  1579.                         LA_Chars,    60,
  1580.                         LAST_Picker,    LoadGadget,
  1581.                     TAG_DONE);
  1582.                 }
  1583.  
  1584.                 LT_EndGroup(Handle);
  1585.             }
  1586.  
  1587.             LT_New(Handle,
  1588.                 LA_Type,VERTICAL_KIND,
  1589.             TAG_DONE);
  1590.             {
  1591.                 LT_New(Handle,
  1592.                     LA_Type,    XBAR_KIND,
  1593.                     LAXB_FullSize,    TRUE,
  1594.                 TAG_DONE);
  1595.  
  1596.                 LT_EndGroup(Handle);
  1597.             }
  1598.  
  1599.             LT_New(Handle,LA_Type,HORIZONTAL_KIND,
  1600.                 LAGR_SameSize,    TRUE,
  1601.                 LAGR_Spread,    TRUE,
  1602.             TAG_DONE);
  1603.             {
  1604.                 LT_New(Handle,
  1605.                     LA_Type,    BUTTON_KIND,
  1606.                     LA_LabelID,    MSG_TERMXPR_OKAY_GAD,
  1607.                     LA_ID,        GAD_OK,
  1608.                     LABT_ReturnKey,    TRUE,
  1609.                     LABT_ExtraFat,    TRUE,
  1610.                 TAG_DONE);
  1611.  
  1612.                 LT_New(Handle,
  1613.                     LA_Type,    BUTTON_KIND,
  1614.                     LA_LabelID,    MSG_GLOBAL_CANCEL_GAD,
  1615.                     LA_ID,        GAD_CANCEL,
  1616.                     LABT_EscKey,    TRUE,
  1617.                     LABT_ExtraFat,    TRUE,
  1618.                 TAG_DONE);
  1619.  
  1620.                 LT_EndGroup(Handle);
  1621.             }
  1622.         }
  1623.  
  1624.         if(PanelWindow = LT_Build(Handle,
  1625.             LAWN_TitleID,        MSG_GLOBAL_ENTER_TEXT_TXT,
  1626.             LAWN_IDCMP,        IDCMP_CLOSEWINDOW,
  1627.             LAWN_HelpHook,        &GuideHook,
  1628.             LAWN_Parent,        Window,
  1629.             WA_DepthGadget,        TRUE,
  1630.             WA_CloseGadget,        TRUE,
  1631.             WA_DragBar,        TRUE,
  1632.             WA_RMBTrap,        TRUE,
  1633.             WA_Activate,        TRUE,
  1634.             WA_SimpleRefresh,    TRUE,
  1635.         TAG_DONE))
  1636.         {
  1637.             struct IntuiMessage    *Message;
  1638.             BOOLEAN             Done = FALSE;
  1639.             ULONG             MsgClass;
  1640.             UWORD             MsgCode;
  1641.             struct Gadget        *MsgGadget;
  1642.  
  1643.             LT_Activate(Handle,GAD_STRING);
  1644.  
  1645.             PushWindow(PanelWindow);
  1646.  
  1647.             LT_ShowWindow(Handle,TRUE);
  1648.  
  1649.             do
  1650.             {
  1651.                 if(Wait(PORTMASK(PanelWindow -> UserPort) | SIG_BREAK) & SIG_BREAK)
  1652.                     break;
  1653.  
  1654.                 while(Message = (struct IntuiMessage *)LT_GetIMsg(Handle))
  1655.                 {
  1656.                     MsgClass    = Message -> Class;
  1657.                     MsgCode        = Message -> Code;
  1658.                     MsgGadget    = (struct Gadget *)Message -> IAddress;
  1659.  
  1660.                     LT_ReplyIMsg(Message);
  1661.  
  1662.                     if(MsgClass == IDCMP_CLOSEWINDOW)
  1663.                         Done = TRUE;
  1664.  
  1665.                     if(MsgClass == IDCMP_GADGETUP)
  1666.                     {
  1667.                         switch(MsgGadget -> GadgetID)
  1668.                         {
  1669.                             case GAD_STRING:
  1670.  
  1671.                                 if(MsgCode == '\r')
  1672.                                 {
  1673.                                     LT_UpdateStrings(Handle);
  1674.  
  1675.                                     strcpy(Buffer,LocalBuffer);
  1676.  
  1677.                                     Success = Done = TRUE;
  1678.  
  1679.                                     LT_PressButton(Handle,GAD_OK);
  1680.                                 }
  1681.  
  1682.                                 break;
  1683.  
  1684.                             case GAD_OK:
  1685.  
  1686.                                 LT_UpdateStrings(Handle);
  1687.  
  1688.                                 strcpy(Buffer,LocalBuffer);
  1689.  
  1690.                                 Success = Done = TRUE;
  1691.                                 break;
  1692.  
  1693.                             case GAD_CANCEL:
  1694.  
  1695.                                 Done = TRUE;
  1696.                                 break;
  1697.                         }
  1698.                     }
  1699.  
  1700.                     if(MsgClass == IDCMP_IDCMPUPDATE && MsgGadget -> GadgetID == GAD_STRING)
  1701.                     {
  1702.                         UBYTE             DummyBuffer[MAX_FILENAME_LENGTH],
  1703.                                     *DummyChar;
  1704.                         struct FileRequester    *FileRequest;
  1705.  
  1706.                         SplitFileName(LocalBuffer,&DummyChar,DummyBuffer);
  1707.  
  1708.                         if(FileRequest = GetFile(PanelWindow,LocaleString(MSG_TERMAUX_LOAD_FILE_TXT),DummyBuffer,DummyChar,DummyBuffer,NULL,FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SELECT_TXT),TRUE))
  1709.                         {
  1710.                             LT_SetAttributes(Handle,GAD_STRING,GTST_String,DummyBuffer,TAG_DONE);
  1711.  
  1712.                             FreeAslRequest(FileRequest);
  1713.                         }
  1714.                     }
  1715.                 }
  1716.             }
  1717.             while(!Done);
  1718.  
  1719.             PopWindow();
  1720.         }
  1721.  
  1722.         LT_DeleteHandle(Handle);
  1723.     }
  1724.  
  1725.     return(Success);
  1726. }
  1727.  
  1728.     /* WakeUp(struct Window *Window,WORD Sound):
  1729.      *
  1730.      *    Pop a window to the front and alert the user.
  1731.      */
  1732.  
  1733. VOID __regargs
  1734. WakeUp(struct Window *Window,WORD Sound)
  1735. {
  1736.     if(Window)
  1737.     {
  1738.         if(Config -> MiscConfig -> AlertMode == ALERT_SCREEN || Config -> MiscConfig -> AlertMode == ALERT_BEEP_SCREEN)
  1739.         {
  1740.             if(Window -> WScreen -> LeftEdge > 0)
  1741.             {
  1742.                 if(Window -> WScreen -> TopEdge > 0)
  1743.                     MoveScreen(Window -> WScreen,-Window -> WScreen -> LeftEdge,-Window -> WScreen -> TopEdge);
  1744.                 else
  1745.                     MoveScreen(Window -> WScreen,-Window -> WScreen -> LeftEdge,0);
  1746.             }
  1747.             else
  1748.             {
  1749.                 if(Window -> WScreen -> TopEdge > 0)
  1750.                     MoveScreen(Window -> WScreen,0,-Window -> WScreen -> TopEdge);
  1751.             }
  1752.  
  1753.             WindowToFront(Window);
  1754.  
  1755.             ScreenToFront(Window -> WScreen);
  1756.         }
  1757.     }
  1758.  
  1759.     if(Sound != SOUND_BELL || Config -> MiscConfig -> AlertMode == ALERT_BEEP || Config -> MiscConfig -> AlertMode == ALERT_BEEP_SCREEN)
  1760.         SoundPlay(Sound);
  1761. }
  1762.  
  1763.     /* TaskDestructor(struct DataMsg *Item):
  1764.      *
  1765.      *    Msg destructor for the routines below.
  1766.      */
  1767.  
  1768. STATIC VOID __stdargs
  1769. TaskDestructor(struct DataMsg *Item)
  1770. {
  1771.     Signal((struct Process *)Item -> Data,SIGBREAKF_CTRL_F);
  1772. }
  1773.  
  1774.     /* AmigaDOSBackgroundServer(VOID):
  1775.      *
  1776.      *    Background process to handle tool execution.
  1777.      */
  1778.  
  1779. STATIC VOID __saveds
  1780. AmigaDOSBackgroundServer(VOID)
  1781. {
  1782.     BPTR         OldCOS,
  1783.              NewCOS = NULL;
  1784.     struct DataMsg     Msg;
  1785.     STRPTR         Command;
  1786.     struct Process    *Me;
  1787.  
  1788.         /* Look who we are. */
  1789.  
  1790.     Me = (struct Process *)SysBase -> ThisTask;
  1791.  
  1792.     Command = Me -> pr_Task . tc_UserData;
  1793.  
  1794.         /* Create console output stream, will be closed automagically on exit. */
  1795.  
  1796.     if(!Me -> pr_COS && Me -> pr_ConsoleTask)
  1797.     {
  1798.         if(NewCOS = Open("*",MODE_NEWFILE))
  1799.         {
  1800.             OldCOS = Me -> pr_COS;
  1801.  
  1802.             Me -> pr_COS = NewCOS;
  1803.         }
  1804.     }
  1805.  
  1806.     SystemTags(Command,
  1807.         SYS_UserShell,    TRUE,
  1808.     TAG_DONE);
  1809.  
  1810.     FreeVecPooled(Command);
  1811.  
  1812.     Forbid();
  1813.  
  1814.     InitMsgItem(&Msg,TaskDestructor);
  1815.  
  1816.     Msg . Type = DATAMSGTYPE_COMMANDDONE;
  1817.     Msg . Data = (UBYTE *)Me;
  1818.  
  1819.     ClrSignal(SIGBREAKF_CTRL_F);
  1820.  
  1821.     PutMsgItem(SpecialQueue,(struct MsgItem *)&Msg);
  1822.  
  1823.     Wait(SIGBREAKF_CTRL_F);
  1824.  
  1825.     if(NewCOS)
  1826.     {
  1827.         Me -> pr_COS = OldCOS;
  1828.  
  1829.         Close(NewCOS);
  1830.     }
  1831. }
  1832.  
  1833.     /* SendAmigaDOSCommand(STRPTR Name):
  1834.      *
  1835.      *    Let the current default Shell execute an AmigaDOS
  1836.      *    command. Block until the command has returned.
  1837.      */
  1838.  
  1839. VOID __regargs
  1840. SendAmigaDOSCommand(STRPTR Name)
  1841. {
  1842.     STRPTR NewName;
  1843.  
  1844.     if(NewName = (STRPTR)AllocVecPooled(strlen(Name) + 1 + 256,MEMF_ANY))
  1845.     {
  1846.         struct Process    *NewProcess;
  1847.         BPTR         Stream;
  1848.         STRPTR         NewWindowName;
  1849.  
  1850.         strcpy(NewName,Name);
  1851.  
  1852.         NewWindowName = NewName + strlen(NewName) + 1;
  1853.  
  1854.         BlockWindows();
  1855.  
  1856.         SetQueueDiscard(SpecialQueue,FALSE);
  1857.  
  1858.             /* Open the output file. */
  1859.  
  1860.         if(WindowName[0])
  1861.         {
  1862.             UBYTE LocalName[MAXPUBSCREENNAME + 1];
  1863.  
  1864.             if(Window)
  1865.             {
  1866.                 if(!GetPubScreenName(Window -> WScreen,LocalName))
  1867.                     LocalName[0] = 0;
  1868.             }
  1869.  
  1870.             if(LocalName[0])
  1871.             {
  1872.                 SPrintf(NewWindowName,WindowName,LocalName);
  1873.  
  1874.                 Stream = Open(NewWindowName,MODE_NEWFILE);
  1875.             }
  1876.             else
  1877.                 Stream = Open(WindowName,MODE_NEWFILE);
  1878.         }
  1879.         else
  1880.             Stream = NULL;
  1881.  
  1882.         Forbid();
  1883.  
  1884.         if(Stream)
  1885.         {
  1886.             if(GoodStream(Stream))
  1887.             {
  1888.                 struct FileHandle *Handle = (struct FileHandle *)BADDR(Stream);
  1889.  
  1890.                 NewProcess = (struct Process *)CreateNewProcTags(
  1891.                     NP_Entry,    AmigaDOSBackgroundServer,
  1892.                     NP_Name,    "term AmigaDOS Background Process",
  1893.                     NP_Input,    Stream,
  1894.                     NP_Output,    NULL,
  1895.                     NP_Cli,        TRUE,
  1896.                     NP_ConsoleTask,    Handle -> fh_Type,
  1897.                     NP_StackSize,    16384,
  1898.                 TAG_END);
  1899.             }
  1900.             else
  1901.             {
  1902.                 NewProcess = (struct Process *)CreateNewProcTags(
  1903.                     NP_Entry,    AmigaDOSBackgroundServer,
  1904.                     NP_Name,    "term AmigaDOS Background Process",
  1905.                     NP_Output,    Stream,
  1906.                     NP_Cli,        TRUE,
  1907.                     NP_ConsoleTask,    NULL,
  1908.                     NP_StackSize,    16384,
  1909.                 TAG_END);
  1910.             }
  1911.         }
  1912.         else
  1913.         {
  1914.             NewProcess = (struct Process *)CreateNewProcTags(
  1915.                 NP_Entry,    AmigaDOSBackgroundServer,
  1916.                 NP_Name,    "term AmigaDOS Background Process",
  1917.                 NP_Cli,        TRUE,
  1918.                 NP_ConsoleTask,    NULL,
  1919.                 NP_StackSize,    16384,
  1920.             TAG_END);
  1921.         }
  1922.  
  1923.             /* Did we succeed in creating the process? */
  1924.  
  1925.         if(NewProcess)
  1926.         {
  1927.             CantQuit++;
  1928.  
  1929.             NewProcess -> pr_Task . tc_UserData = NewName;
  1930.  
  1931.             Permit();
  1932.         }
  1933.         else
  1934.         {
  1935.             Permit();
  1936.  
  1937.             if(Stream)
  1938.                 Close(Stream);
  1939.  
  1940.             FreeVecPooled(NewName);
  1941.  
  1942.             BumpWindow(Window);
  1943.  
  1944.             ReleaseWindows();
  1945.         }
  1946.     }
  1947. }
  1948.  
  1949.     /* RexxBackgroundServer():
  1950.      *
  1951.      *    The background process to handle the rexx
  1952.      *    massaging.
  1953.      */
  1954.  
  1955. STATIC VOID __saveds
  1956. RexxBackgroundServer(VOID)
  1957. {
  1958.     struct MsgPort     *RexxPort;
  1959.     BPTR         OldCOS,
  1960.              NewCOS = NULL;
  1961.     struct DataMsg     Msg;
  1962.     STRPTR         Command;
  1963.     struct Process    *Me;
  1964.  
  1965.         /* Look who we are. */
  1966.  
  1967.     Me = (struct Process *)SysBase -> ThisTask;
  1968.  
  1969.     Command = Me -> pr_Task . tc_UserData;
  1970.  
  1971.         /* Create console output stream, will be closed automagically on exit. */
  1972.  
  1973.     if(!Me -> pr_COS && Me -> pr_ConsoleTask)
  1974.     {
  1975.         if(NewCOS = Open("*",MODE_NEWFILE))
  1976.         {
  1977.             OldCOS = Me -> pr_COS;
  1978.  
  1979.             Me -> pr_COS = NewCOS;
  1980.         }
  1981.     }
  1982.  
  1983.     if(RexxPort = FindPort(RXSDIR))
  1984.     {
  1985.         struct MsgPort __aligned     ReplyPort;
  1986.         struct RexxMsg            *RexxMsg;
  1987.  
  1988.         InitSinglePort(&ReplyPort);
  1989.  
  1990.         if(RexxMsg = CreateRexxMsg(&ReplyPort,"term",RexxPortName))
  1991.         {
  1992.             if(RexxMsg -> rm_Args[0] = CreateArgstring(Command,strlen(Command)))
  1993.             {
  1994.                 RexxMsg -> rm_Action = RXCOMM;
  1995.  
  1996.                 Forbid();
  1997.  
  1998.                 ClrSignal(SIGF_SINGLE);
  1999.  
  2000.                 PutMsg(RexxPort,(struct Message *)RexxMsg);
  2001.  
  2002.                 WaitPort(&ReplyPort);
  2003.  
  2004.                 GetMsg(&ReplyPort);
  2005.  
  2006.                 Permit();
  2007.  
  2008.                     /* This doesn't look too
  2009.                      * good, does it?
  2010.                      */
  2011.  
  2012.                 if(RexxMsg -> rm_Result1 && Me -> pr_COS)
  2013.                     Printf(LocaleString(MSG_TERMAUX_COMMAND_HAS_TERMINATED_TXT),Command,RexxMsg -> rm_Result1,RexxMsg -> rm_Result2);
  2014.  
  2015.                 DeleteArgstring(RexxMsg -> rm_Args[0]);
  2016.             }
  2017.  
  2018.             DeleteRexxMsg(RexxMsg);
  2019.         }
  2020.     }
  2021.  
  2022.     FreeVecPooled(Command);
  2023.  
  2024.     Forbid();
  2025.  
  2026.     InitMsgItem(&Msg,TaskDestructor);
  2027.  
  2028.     Msg . Type = DATAMSGTYPE_COMMANDDONE;
  2029.     Msg . Data = (UBYTE *)Me;
  2030.  
  2031.     ClrSignal(SIGBREAKF_CTRL_F);
  2032.  
  2033.     PutMsgItem(SpecialQueue,(struct MsgItem *)&Msg);
  2034.  
  2035.     Wait(SIGBREAKF_CTRL_F);
  2036.  
  2037.     if(NewCOS)
  2038.     {
  2039.         Me -> pr_COS = OldCOS;
  2040.  
  2041.         Close(NewCOS);
  2042.     }
  2043. }
  2044.  
  2045.     /* SendARexxCommand(STRPTR Name,BOOL QueueIt):
  2046.      *
  2047.      *    Let the ARexx server execute a command (or a script
  2048.      *    file if necessary) and block until the command
  2049.      *    has returned.
  2050.      */
  2051.  
  2052. VOID __regargs
  2053. SendARexxCommand(STRPTR Name,BOOL QueueIt)
  2054. {
  2055.     STRPTR NewName;
  2056.  
  2057.     if(QueueIt)
  2058.     {
  2059.         ObtainSemaphore(&ARexxQueueSemaphore);
  2060.  
  2061.         if(ARexxRunning)
  2062.         {
  2063.             struct Node *Node;
  2064.  
  2065.             if(Node = CreateNode(Name))
  2066.                 AddTail(&ARexxQueue,Node);
  2067.  
  2068.             ReleaseSemaphore(&ARexxQueueSemaphore);
  2069.  
  2070.             return;
  2071.         }
  2072.     }
  2073.  
  2074.     if(NewName = (STRPTR)AllocVecPooled(strlen(Name) + 1 + 256,MEMF_ANY))
  2075.     {
  2076.         struct Process    *NewProcess;
  2077.         BPTR         Stream;
  2078.         STRPTR         NewWindowName;
  2079.  
  2080.         strcpy(NewName,Name);
  2081.  
  2082.         NewWindowName = NewName + strlen(NewName) + 1;
  2083.  
  2084.         BlockWindows();
  2085.  
  2086.         SetQueueDiscard(SpecialQueue,FALSE);
  2087.  
  2088.             /* Open the output file. */
  2089.  
  2090.         if(WindowName[0])
  2091.         {
  2092.             UBYTE LocalName[MAXPUBSCREENNAME + 1];
  2093.  
  2094.             if(Window)
  2095.             {
  2096.                 if(!GetPubScreenName(Window -> WScreen,LocalName))
  2097.                     LocalName[0] = 0;
  2098.             }
  2099.  
  2100.             if(LocalName[0])
  2101.             {
  2102.                 SPrintf(NewWindowName,WindowName,LocalName);
  2103.  
  2104.                 Stream = Open(NewWindowName,MODE_NEWFILE);
  2105.             }
  2106.             else
  2107.                 Stream = Open(WindowName,MODE_NEWFILE);
  2108.         }
  2109.         else
  2110.             Stream = NULL;
  2111.  
  2112.         Forbid();
  2113.  
  2114.             /* Create the background process which will
  2115.              * handle all the messy rexx message sending
  2116.              * for us.
  2117.              */
  2118.  
  2119.         if(Stream)
  2120.         {
  2121.             if(GoodStream(Stream))
  2122.             {
  2123.                 struct FileHandle *Handle = (struct FileHandle *)BADDR(Stream);
  2124.  
  2125.                 NewProcess = (struct Process *)CreateNewProcTags(
  2126.                     NP_Entry,    RexxBackgroundServer,
  2127.                     NP_Name,    "term ARexx Background Process",
  2128.                     NP_Input,    Stream,
  2129.                     NP_Output,    NULL,
  2130.                     NP_Cli,        TRUE,
  2131.                     NP_ConsoleTask,    Handle -> fh_Type,
  2132.                     NP_StackSize,    16384,
  2133.                 TAG_END);
  2134.             }
  2135.             else
  2136.             {
  2137.                 NewProcess = (struct Process *)CreateNewProcTags(
  2138.                     NP_Entry,    RexxBackgroundServer,
  2139.                     NP_Name,    "term ARexx Background Process",
  2140.                     NP_Output,    Stream,
  2141.                     NP_Cli,        TRUE,
  2142.                     NP_ConsoleTask,    NULL,
  2143.                     NP_StackSize,    16384,
  2144.                 TAG_END);
  2145.             }
  2146.         }
  2147.         else
  2148.         {
  2149.             NewProcess = (struct Process *)CreateNewProcTags(
  2150.                 NP_Entry,    RexxBackgroundServer,
  2151.                 NP_Name,    "term ARexx Background Process",
  2152.                 NP_Cli,        TRUE,
  2153.                 NP_ConsoleTask,    NULL,
  2154.                 NP_StackSize,    16384,
  2155.             TAG_END);
  2156.         }
  2157.  
  2158.             /* Did we succeed in creating the process? */
  2159.  
  2160.         if(NewProcess)
  2161.         {
  2162.             CantQuit++;
  2163.  
  2164.             NewProcess -> pr_Task . tc_UserData = NewName;
  2165.  
  2166.             Permit();
  2167.  
  2168.             if(QueueIt)
  2169.                 ARexxRunning = TRUE;
  2170.         }
  2171.         else
  2172.         {
  2173.             Permit();
  2174.  
  2175.             if(Stream)
  2176.                 Close(Stream);
  2177.  
  2178.             FreeVecPooled(NewName);
  2179.  
  2180.             BumpWindow(Window);
  2181.  
  2182.             ReleaseWindows();
  2183.         }
  2184.     }
  2185.  
  2186.     if(QueueIt)
  2187.         ReleaseSemaphore(&ARexxQueueSemaphore);
  2188. }
  2189.  
  2190.     /* BlockWindows():
  2191.      *
  2192.      *    Block the main window and the status window (i.e. disable
  2193.      *    the menu and attach a wait pointer).
  2194.      */
  2195.  
  2196. VOID
  2197. BlockWindows()
  2198. {
  2199.     if(!(BlockNestCount++))
  2200.     {
  2201.         LT_LockWindow(Window);
  2202.         LT_LockWindow(StatusWindow);
  2203.         LT_LockWindow(FastWindow);
  2204.         LT_LockWindow(MatrixWindow);
  2205.  
  2206.         WeAreBlocking = TRUE;
  2207.  
  2208.         SetQueueDiscard(SpecialQueue,TRUE);
  2209.  
  2210.         GhostCursor();
  2211.     }
  2212. }
  2213.  
  2214.     /* ReleaseWindows():
  2215.      *
  2216.      *    Reenable the menus and clear the wait pointer.
  2217.      */
  2218.  
  2219. VOID
  2220. ReleaseWindows()
  2221. {
  2222.     if(BlockNestCount == 1)
  2223.     {
  2224.         LT_UnlockWindow(Window);
  2225.         LT_UnlockWindow(StatusWindow);
  2226.         LT_UnlockWindow(FastWindow);
  2227.         LT_UnlockWindow(MatrixWindow);
  2228.  
  2229.         WeAreBlocking = FALSE;
  2230.  
  2231.         SetQueueDiscard(SpecialQueue,FALSE);
  2232.  
  2233.         if(Window)
  2234.         {
  2235.             Forbid();
  2236.  
  2237.             if(Window -> Flags & WFLG_WINDOWACTIVE)
  2238.                 NormalCursor();
  2239.  
  2240.             Permit();
  2241.         }
  2242.     }
  2243.  
  2244.     if(BlockNestCount)
  2245.         BlockNestCount--;
  2246. }
  2247.  
  2248.     /* LineRead(BPTR File,STRPTR Buffer,LONG MaxChars):
  2249.      *
  2250.      *    Read a few bytes from a file (à la gets).
  2251.      */
  2252.  
  2253. LONG __regargs
  2254. LineRead(BPTR File,STRPTR Buffer,LONG MaxChars)
  2255. {
  2256.     STATIC UBYTE __far    Data[1024];
  2257.     STATIC LONG        ReadIndex    = 0,
  2258.                 ReadLen        = 0;
  2259.  
  2260.     if(File)
  2261.     {
  2262.         LONG BytesRead = 0,i;
  2263.  
  2264.         for(i = 0 ; i < MaxChars ; i++)
  2265.         {
  2266.             if(ReadIndex >= ReadLen)
  2267.             {
  2268.                 ReadLen = Read(File,Data,1024);
  2269.  
  2270.                 ReadIndex = 0;
  2271.  
  2272.                 if(ReadLen <= 0)
  2273.                 {
  2274.                     Buffer[i] = 0;
  2275.  
  2276.                     return(BytesRead);
  2277.                 }
  2278.             }
  2279.  
  2280.             BytesRead++;
  2281.  
  2282.             if((Buffer[i] = Data[ReadIndex++]) == '\n')
  2283.             {
  2284.                 Buffer[i + 1] = 0;
  2285.  
  2286.                 return(BytesRead);
  2287.             }
  2288.         }
  2289.  
  2290.         return(BytesRead);
  2291.     }
  2292.     else
  2293.         ReadIndex = ReadLen = 0;
  2294. }
  2295.  
  2296.     /* GetBaudRate(STRPTR Buffer):
  2297.      *
  2298.      *    Calculate the baud rate contained in a connect string.
  2299.      */
  2300.  
  2301. LONG __regargs
  2302. GetBaudRate(STRPTR Buffer)
  2303. {
  2304.     LONG Rate,i,j;
  2305.  
  2306.     for(i = j = 0 ; i < strlen(Buffer) ; i++)
  2307.     {
  2308.         if(Buffer[i] == ' ')
  2309.             continue;
  2310.         else
  2311.         {
  2312.             if(Buffer[i] >= '0' && Buffer[i] <= '9')
  2313.                 SharedBuffer[j++] = Buffer[i];
  2314.             else
  2315.                 break;
  2316.         }
  2317.     }
  2318.  
  2319.     SharedBuffer[j] = 0;
  2320.  
  2321.     if(StrToLong(SharedBuffer,&Rate) > 0)
  2322.     {
  2323.         if(Rate > 0)
  2324.             return(Rate);
  2325.     }
  2326.  
  2327.     return(0);
  2328. }
  2329.  
  2330.     /* LookForIt(struct MenuItem *Item,ULONG ID):
  2331.      *
  2332.      *    Auxilary routine for FindThisItem(), scans
  2333.      *    menu item and sub item lists.
  2334.      */
  2335.  
  2336. STATIC struct MenuItem * __inline
  2337. LookForIt(struct MenuItem *Item,ULONG ID)
  2338. {
  2339.     while(Item)
  2340.     {
  2341.         if((ULONG)GTMENUITEM_USERDATA(Item) == ID)
  2342.             return(Item);
  2343.         else
  2344.         {
  2345.             if(Item -> SubItem)
  2346.             {
  2347.                 register struct MenuItem *TheItem;
  2348.  
  2349.                 if(TheItem = LookForIt(Item -> SubItem,ID))
  2350.                     return(TheItem);
  2351.             }
  2352.  
  2353.             Item = Item -> NextItem;
  2354.         }
  2355.     }
  2356.  
  2357.     return(NULL);
  2358. }
  2359.  
  2360.     /* FindThisItem(struct Menu *FirstMenu,ULONG MenuID):
  2361.      *
  2362.      *    Scan a menu for a menuitem associated with a
  2363.      *    menu ID.
  2364.      */
  2365.  
  2366. struct MenuItem * __regargs
  2367. FindThisItem(struct Menu *FirstMenu,ULONG MenuID)
  2368. {
  2369.     if(TypeOfMem(FirstMenu))
  2370.     {
  2371.         struct MenuItem *Item;
  2372.  
  2373.         while(FirstMenu)
  2374.         {
  2375.             if(Item = LookForIt(FirstMenu -> FirstItem,MenuID))
  2376.                 return(Item);
  2377.             else
  2378.                 FirstMenu = FirstMenu -> NextMenu;
  2379.         }
  2380.     }
  2381.  
  2382.     return(NULL);
  2383. }
  2384.  
  2385. struct Menu * __regargs
  2386. FindThisMenu(struct Menu *FirstMenu,ULONG MenuID)
  2387. {
  2388.     if(TypeOfMem(FirstMenu))
  2389.     {
  2390.         while(FirstMenu)
  2391.         {
  2392.             if(GTMENU_USERDATA(FirstMenu) == (APTR)MenuID)
  2393.                 return(FirstMenu);
  2394.             else
  2395.                 FirstMenu = FirstMenu -> NextMenu;
  2396.         }
  2397.     }
  2398.  
  2399.     return(NULL);
  2400. }
  2401.  
  2402.     /* GetItem(ULONG MenuID):
  2403.      *
  2404.      *    Get the checkmark state of a menu item.
  2405.      */
  2406.  
  2407. BYTE __regargs
  2408. GetItem(ULONG MenuID)
  2409. {
  2410.     if(Menu)
  2411.     {
  2412.         struct MenuItem *Item;
  2413.  
  2414.         if(Item = FindThisItem(Menu,MenuID))
  2415.         {
  2416.             if(Item -> Flags & CHECKED)
  2417.                 return(TRUE);
  2418.         }
  2419.     }
  2420.  
  2421.     return(FALSE);
  2422. }
  2423.  
  2424.     /* SetItem(ULONG MenuID,BYTE Mode):
  2425.      *
  2426.      *    Clear or set the checkmark or state of a menu item.
  2427.      */
  2428.  
  2429. VOID __regargs
  2430. SetItem(ULONG MenuID,BYTE Mode)
  2431. {
  2432.         /* Is the global pull-down menu available? */
  2433.  
  2434.     if(Menu)
  2435.     {
  2436.         struct MenuItem    *Item;
  2437.         struct Menu    *ThisMenu;
  2438.  
  2439.         if(ThisMenu = FindThisMenu(Menu,MenuID))
  2440.         {
  2441.                 /* Remove the menu from the windows. */
  2442.  
  2443.             if(Window)
  2444.                 ClearMenuStrip(Window);
  2445.  
  2446.             if(StatusWindow)
  2447.                 ClearMenuStrip(StatusWindow);
  2448.  
  2449.             if(FastWindow)
  2450.                 ClearMenuStrip(FastWindow);
  2451.  
  2452.             switch(Mode)
  2453.             {
  2454.                 case SETITEM_ON:
  2455.  
  2456.                     ThisMenu -> Flags |= MENUENABLED;
  2457.                     break;
  2458.  
  2459.                 case SETITEM_OFF:
  2460.  
  2461.                     ThisMenu -> Flags &= ~MENUENABLED;
  2462.                     break;
  2463.             }
  2464.  
  2465.                 /* Reattach the menu to the windows. */
  2466.  
  2467.             if(Window)
  2468.                 ResetMenuStrip(Window,Menu);
  2469.  
  2470.             if(StatusWindow)
  2471.                 ResetMenuStrip(StatusWindow,Menu);
  2472.  
  2473.             if(FastWindow)
  2474.                 ResetMenuStrip(FastWindow,Menu);
  2475.  
  2476.             return;
  2477.         }
  2478.  
  2479.             /* Try to find the menu item and change
  2480.              * the state of the checkmark.
  2481.              */
  2482.  
  2483.         if(Item = FindThisItem(Menu,MenuID))
  2484.         {
  2485.                 /* Remove the menu from the windows. */
  2486.  
  2487.             if(Window)
  2488.                 ClearMenuStrip(Window);
  2489.  
  2490.             if(StatusWindow)
  2491.                 ClearMenuStrip(StatusWindow);
  2492.  
  2493.             if(FastWindow)
  2494.                 ClearMenuStrip(FastWindow);
  2495.  
  2496.             switch(Mode)
  2497.             {
  2498.                 case SETITEM_SETCHECK:
  2499.  
  2500.                     Item -> Flags |= CHECKED;
  2501.                     break;
  2502.  
  2503.                 case SETITEM_CLRCHECK:
  2504.  
  2505.                     Item -> Flags &= ~CHECKED;
  2506.                     break;
  2507.  
  2508.                 case SETITEM_ON:
  2509.  
  2510.                     Item -> Flags |= ITEMENABLED;
  2511.                     break;
  2512.  
  2513.                 case SETITEM_OFF:
  2514.  
  2515.                     Item -> Flags &= ~ITEMENABLED;
  2516.                     break;
  2517.             }
  2518.  
  2519.                 /* Reattach the menu to the windows. */
  2520.  
  2521.             if(Window)
  2522.                 ResetMenuStrip(Window,Menu);
  2523.  
  2524.             if(StatusWindow)
  2525.                 ResetMenuStrip(StatusWindow,Menu);
  2526.  
  2527.             if(FastWindow)
  2528.                 ResetMenuStrip(FastWindow,Menu);
  2529.         }
  2530.     }
  2531. }
  2532.  
  2533.     /* GetFileSize(STRPTR Name):
  2534.      *
  2535.      *    Simple routine to return the size of a file in
  2536.      *    bytes.
  2537.      */
  2538.  
  2539. LONG __regargs
  2540. GetFileSize(STRPTR Name)
  2541. {
  2542.     struct FileInfoBlock    *FileInfo;
  2543.     LONG             FileSize = 0;
  2544.  
  2545.     if(FileInfo = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_DONE))
  2546.     {
  2547.         BPTR FileLock;
  2548.  
  2549.         if(FileLock = Lock(Name,ACCESS_READ))
  2550.         {
  2551.             if(Examine(FileLock,FileInfo))
  2552.             {
  2553.                 if(FileInfo -> fib_DirEntryType < 0)
  2554.                     FileSize = FileInfo -> fib_Size;
  2555.             }
  2556.  
  2557.             UnLock(FileLock);
  2558.         }
  2559.  
  2560.         FreeDosObject(DOS_FIB,FileInfo);
  2561.     }
  2562.  
  2563.     return(FileSize);
  2564. }
  2565.  
  2566.     /* PutDimensionTags(struct Window *Reference,LONG Left,LONG Top,LONG Width,LONG Height):
  2567.      *
  2568.      *    Put back the default values for the requesters to open.
  2569.      */
  2570.  
  2571. VOID __regargs
  2572. PutDimensionTags(struct Window *Reference,LONG Left,LONG Top,LONG Width,LONG Height)
  2573. {
  2574.     if(Config -> MiscConfig -> RequesterMode != REQUESTERMODE_IGNORE && (!Config -> MiscConfig -> RequesterWidth || !Config -> MiscConfig -> RequesterHeight))
  2575.     {
  2576.         if(!Reference)
  2577.             Reference = Window;
  2578.  
  2579.         Config -> MiscConfig -> RequesterLeft    = Left    - Reference -> LeftEdge;
  2580.         Config -> MiscConfig -> RequesterTop    = Top    - Reference -> TopEdge;
  2581.         Config -> MiscConfig -> RequesterWidth    = Width;
  2582.         Config -> MiscConfig -> RequesterHeight    = Height;
  2583.     }
  2584. }
  2585.  
  2586.     /* GetDimensionTags(struct Window *Reference,struct TagItem *Tags):
  2587.      *
  2588.      *    Fills an array of tagitems with the dimensions of an asl requester
  2589.      *    to be opened.
  2590.      */
  2591.  
  2592. struct TagItem * __regargs
  2593. GetDimensionTags(struct Window *Reference,struct TagItem *Tags)
  2594. {
  2595.     if(Config -> MiscConfig -> RequesterMode == REQUESTERMODE_IGNORE || !Config -> MiscConfig -> RequesterWidth || !Config -> MiscConfig -> RequesterHeight)
  2596.     {
  2597.         STATIC ULONG Done = TAG_DONE;
  2598.  
  2599.         return((struct TagItem *)&Done);
  2600.     }
  2601.     else
  2602.     {
  2603.         LONG Left,Top,Width,Height;
  2604.  
  2605.         if(!Reference)
  2606.             Reference = Window;
  2607.  
  2608.         if(Config -> MiscConfig -> RequesterMode == REQUESTERMODE_CENTRE)
  2609.         {
  2610.             Left    = Reference -> LeftEdge    + (Reference -> Width - Config -> MiscConfig -> RequesterWidth) / 2;
  2611.             Top    = Reference -> TopEdge    + (Reference -> Height - Config -> MiscConfig -> RequesterHeight) / 2;
  2612.         }
  2613.         else
  2614.         {
  2615.             Left    = Config -> MiscConfig -> RequesterLeft    + Reference -> LeftEdge;
  2616.             Top    = Config -> MiscConfig -> RequesterTop    + Reference -> TopEdge;
  2617.         }
  2618.  
  2619.         Width    = Config -> MiscConfig -> RequesterWidth;
  2620.         Height    = Config -> MiscConfig -> RequesterHeight;
  2621.  
  2622.         Tags[0] . ti_Tag    = ASL_LeftEdge;
  2623.         Tags[0] . ti_Data    = Left;
  2624.         Tags[1] . ti_Tag    = ASL_TopEdge;
  2625.         Tags[1] . ti_Data    = Top;
  2626.         Tags[2] . ti_Tag    = ASL_Width;
  2627.         Tags[2] . ti_Data    = Width;
  2628.         Tags[3] . ti_Tag    = ASL_Height;
  2629.         Tags[3] . ti_Data    = Height;
  2630.         Tags[4] . ti_Data    = TAG_DONE;
  2631.  
  2632.         return(Tags);
  2633.     }
  2634. }
  2635.  
  2636.     /* GetFile(STRPTR Title,STRPTR Directory,STRPTR Name,STRPTR Buffer,STRPTR Pattern,BYTE SaveFlag,BYTE MultiSelect):
  2637.      *
  2638.      *    Call the asl.library file requester to select a single or
  2639.      *    a couple of files.
  2640.      */
  2641.  
  2642. struct FileRequester * __regargs
  2643. GetFile(struct Window *Parent,STRPTR Title,STRPTR Directory,STRPTR Name,STRPTR Buffer,STRPTR Pattern,BYTE SaveFlag,BYTE MultiSelect,BYTE DirsOnly,STRPTR OKText,BYTE AskWrite)
  2644. {
  2645.     STATIC UBYTE __far     DirBuffer[MAX_FILENAME_LENGTH],
  2646.                  PatternBuffer[60];
  2647.  
  2648.     struct FileRequester    *AslFileRequest;
  2649.     BYTE             Result        = FALSE,
  2650.                  DefaultPattern    = FALSE;
  2651.     LONG             Flags,ExtFlags = 0;
  2652.     WORD             i,j;
  2653.  
  2654.     UBYTE             OtherTitle[60];
  2655.     struct TagItem         DimensionTags[5];
  2656.  
  2657.     if(!Config -> MiscConfig -> ProtectiveMode)
  2658.         AskWrite = FALSE;
  2659.  
  2660.     if(!Parent)
  2661.         Parent = Window;
  2662.  
  2663.     for(i = j = 0 ; i < strlen(Title) ; i++)
  2664.     {
  2665.         if(Title[i] != '_')
  2666.             OtherTitle[j++] = Title[i];
  2667.     }
  2668.  
  2669.     OtherTitle[j] = 0;
  2670.  
  2671.     Title = OtherTitle;
  2672.  
  2673.     if(DirsOnly)
  2674.     {
  2675.         ExtFlags |= FIL1F_NOFILES;
  2676.  
  2677.         if(Pattern)
  2678.             ExtFlags |= FIL1F_MATCHDIRS;
  2679.     }
  2680.  
  2681.         /* Empty directory string? Revert to the last directory
  2682.          * name.
  2683.          */
  2684.  
  2685.     Forbid();
  2686.  
  2687.     if(!Directory[0])
  2688.     {
  2689.         if(!DirBuffer[0])
  2690.         {
  2691.             UBYTE LocalBuffer[MAX_FILENAME_LENGTH];
  2692.  
  2693.             if(!GetCurrentDirName(LocalBuffer,MAX_FILENAME_LENGTH))
  2694.                 LocalBuffer[0] = 0;
  2695.  
  2696.             if(!DirBuffer[0])
  2697.                 strcpy(DirBuffer,LocalBuffer);
  2698.         }
  2699.  
  2700.         Directory = DirBuffer;
  2701.     }
  2702.  
  2703.         /* If a wildcard pattern is required, add a gadget
  2704.          * to display it.
  2705.          */
  2706.  
  2707.     if(Pattern)
  2708.     {
  2709.         Flags = FILF_PATGAD;
  2710.  
  2711.         if(!Pattern[0])
  2712.         {
  2713.             DefaultPattern = TRUE;
  2714.  
  2715.             if(PatternBuffer[0])
  2716.                 Pattern = PatternBuffer;
  2717.             else
  2718.                 Pattern = "#?";
  2719.         }
  2720.         else
  2721.         {
  2722.             if(!Stricmp(Pattern,"#?") || !Stricmp(Pattern,PatternBuffer))
  2723.             {
  2724.                 DefaultPattern = TRUE;
  2725.  
  2726.                 Pattern = PatternBuffer;
  2727.             }
  2728.         }
  2729.     }
  2730.     else
  2731.     {
  2732.         Flags = 0;
  2733.  
  2734.         Pattern = "#?";
  2735.     }
  2736.  
  2737.     Permit();
  2738.  
  2739.         /* Set the save flag if we are about to save something. */
  2740.  
  2741.     if(SaveFlag)
  2742.         Flags |= FILF_SAVE;
  2743.  
  2744.         /* Set the multiselect bit if multiple files are
  2745.          * to be selected (e.g. for batch file upload).
  2746.          */
  2747.  
  2748.     if(MultiSelect)
  2749.         Flags |= FILF_MULTISELECT;
  2750.  
  2751.         /* Provide a standard `Ok' text if none
  2752.          * specified.
  2753.          */
  2754.  
  2755.     if(!OKText)
  2756.         OKText = (SaveFlag ? LocaleString(MSG_GLOBAL_SAVE_TXT) : LocaleString(MSG_GLOBAL_OPEN_TXT));
  2757.  
  2758.         /* Allocate the asl.library directory requester
  2759.          * and display it.
  2760.          */
  2761.  
  2762.     if(AslFileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  2763.         ASLFR_Window,        Parent,
  2764.         ASLFR_InitialFile,    Name,
  2765.         ASLFR_InitialDrawer,    Directory,
  2766.         ASLFR_Flags1,        Flags | FILF_NEWIDCMP,
  2767.         ASLFR_InitialPattern,    Pattern,
  2768.         ASLFR_PositiveText,    OKText,
  2769.         ASLFR_Flags2,        ExtFlags,
  2770.         ASLFR_TextAttr,        &UserFont,
  2771.         ASLFR_PrivateIDCMP,    TRUE,
  2772.  
  2773.         Title ? ASLFR_TitleText : TAG_IGNORE,Title,
  2774.     TAG_MORE,GetDimensionTags(NULL,DimensionTags)))
  2775.     {
  2776.         LT_LockWindow(Parent);
  2777.  
  2778.         if(AslRequest(AslFileRequest,NULL))
  2779.         {
  2780.             PutDimensionTags(NULL,AslFileRequest -> fr_LeftEdge,AslFileRequest -> fr_TopEdge,AslFileRequest -> fr_Width,AslFileRequest -> fr_Height);
  2781.  
  2782.             if(!DirsOnly)
  2783.             {
  2784.                 STRPTR FileName;
  2785.  
  2786.                 if(AslFileRequest -> fr_NumArgs > 1 && AslFileRequest -> fr_ArgList)
  2787.                     FileName = AslFileRequest -> fr_ArgList -> wa_Name;
  2788.                 else
  2789.                     FileName = AslFileRequest -> fr_File;
  2790.  
  2791.                     /* Do we have a valid file name? */
  2792.  
  2793.                 if(FileName)
  2794.                 {
  2795.                         /* Build a legal path/file string. */
  2796.  
  2797.                     strcpy(Buffer,AslFileRequest -> fr_Drawer);
  2798.  
  2799.                     AddPart((STRPTR)Buffer,FileName,MAX_FILENAME_LENGTH);
  2800.  
  2801.                     Result = TRUE;
  2802.  
  2803.                     Forbid();
  2804.  
  2805.                     strcpy(DirBuffer,AslFileRequest -> fr_Drawer);
  2806.  
  2807.                     Permit();
  2808.                 }
  2809.             }
  2810.             else
  2811.             {
  2812.                 if(AslFileRequest -> fr_Drawer[0])
  2813.                 {
  2814.                     strcpy(Buffer,AslFileRequest -> fr_Drawer);
  2815.  
  2816.                     Result = TRUE;
  2817.  
  2818.                     Forbid();
  2819.  
  2820.                     strcpy(DirBuffer,AslFileRequest -> fr_Drawer);
  2821.  
  2822.                     Permit();
  2823.                 }
  2824.             }
  2825.         }
  2826.  
  2827.         LT_UnlockWindow(Parent);
  2828.     }
  2829.         /* We didn't get a file, no need to keep the
  2830.          * file requester.
  2831.          */
  2832.  
  2833.     if(!Result && AslFileRequest)
  2834.     {
  2835.         FreeAslRequest(AslFileRequest);
  2836.  
  2837.         return(NULL);
  2838.     }
  2839.     else
  2840.     {
  2841.         if(SaveFlag && AskWrite)
  2842.         {
  2843.             if(GetFileSize(Buffer))
  2844.             {
  2845.                 if(!MyEasyRequest(Parent,LocaleString(MSG_GLOBAL_FILE_ALREADY_EXISTS_OVERWRITE_TXT),LocaleString(MSG_GLOBAL_REPLACE_CANCEL_TXT),FilePart(Buffer)))
  2846.                 {
  2847.                     FreeAslRequest(AslFileRequest);
  2848.  
  2849.                     return(NULL);
  2850.                 }
  2851.             }
  2852.         }
  2853.  
  2854.         Forbid();
  2855.  
  2856.         if(DefaultPattern)
  2857.             strcpy(PatternBuffer,AslFileRequest -> fr_Pattern);
  2858.  
  2859.         Permit();
  2860.  
  2861.         return(AslFileRequest);
  2862.     }
  2863. }
  2864.  
  2865.     /* MyEasyRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...):
  2866.      *
  2867.      *    Really quite simple varargs version of Intuition's
  2868.      *    EasyRequest requester.
  2869.      */
  2870.  
  2871. WORD __stdargs
  2872. MyEasyRequest(struct Window *Window,STRPTR Text,STRPTR Gadgets,...)
  2873. {
  2874.     struct EasyStruct    Easy;
  2875.     va_list            VarArgs;
  2876.     LONG            i,GadgetCount;
  2877.  
  2878.     for(i = GadgetCount = 0 ; i < strlen(Gadgets) ; i++)
  2879.     {
  2880.         if(Gadgets[i] == '|')
  2881.             GadgetCount++;
  2882.     }
  2883.  
  2884.         /* Standard data. */
  2885.  
  2886.     Easy . es_StructSize    = sizeof(struct EasyStruct);
  2887.     Easy . es_Flags        = NULL;
  2888.     Easy . es_Title        = LocaleString(MSG_TERMAUX_TERM_REQUEST_TXT);
  2889.     Easy . es_TextFormat    = Text;
  2890.     Easy . es_GadgetFormat    = Gadgets;
  2891.  
  2892.     if(GadgetCount)
  2893.     {
  2894.         WORD Result;
  2895.  
  2896.         if(GTLayoutBase)
  2897.             LT_LockWindow(Window);
  2898.  
  2899.             /* Use the argument array to build the
  2900.              * requester and display it.
  2901.              */
  2902.  
  2903.         va_start(VarArgs,Gadgets);
  2904.         Result = EasyRequestArgs(Window,&Easy,NULL,VarArgs);
  2905.         va_end(VarArgs);
  2906.  
  2907.         if(GTLayoutBase)
  2908.             LT_UnlockWindow(Window);
  2909.  
  2910.         return(Result);
  2911.     }
  2912.     else
  2913.     {
  2914.         struct Window *ReqWindow;
  2915.  
  2916.         if(GTLayoutBase)
  2917.             LT_LockWindow(Window);
  2918.  
  2919.         va_start(VarArgs,Gadgets);
  2920.  
  2921.         if(ReqWindow = BuildEasyRequestArgs(Window,&Easy,IDCMP_RAWKEY,VarArgs))
  2922.         {
  2923.             ULONG    IDCMP;
  2924.             LONG    Result;
  2925.  
  2926.             FOREVER
  2927.             {
  2928.                 WaitPort(ReqWindow -> UserPort);
  2929.  
  2930.                 IDCMP = NULL;
  2931.  
  2932.                 Result = SysReqHandler(ReqWindow,&IDCMP,FALSE);
  2933.  
  2934.                 if(!Result || (Result == -2 && !(IDCMP & IDCMP_RAWKEY)))
  2935.                     break;
  2936.             }
  2937.  
  2938.             FreeSysRequest(ReqWindow);
  2939.         }
  2940.  
  2941.         va_end(VarArgs);
  2942.  
  2943.         if(GTLayoutBase)
  2944.             LT_UnlockWindow(Window);
  2945.  
  2946.         return(0);
  2947.     }
  2948. }
  2949.  
  2950.     /* CloseWindowSafely(struct Window *Window):
  2951.      *
  2952.      *    Close a window freeing all messages pending at
  2953.      *    its user port (taken from example source code
  2954.      *    published once upon a time in Amiga Mail).
  2955.      */
  2956.  
  2957. VOID __regargs
  2958. CloseWindowSafely(struct Window *Window)
  2959. {
  2960.     Forbid();
  2961.  
  2962.     if(Window -> UserPort)
  2963.     {
  2964.         struct IntuiMessage    *IntuiMessage;
  2965.         struct Node        *Successor;
  2966.  
  2967.         IntuiMessage = (struct IntuiMessage *)Window -> UserPort -> mp_MsgList . lh_Head;
  2968.  
  2969.         while(Successor = IntuiMessage -> ExecMessage . mn_Node . ln_Succ)
  2970.         {
  2971.             if(IntuiMessage -> IDCMPWindow == Window)
  2972.             {
  2973.                 Remove(IntuiMessage);
  2974.  
  2975.                 ReplyMsg((struct Message *)IntuiMessage);
  2976.             }
  2977.  
  2978.             IntuiMessage = (struct IntuiMessage *)Successor;
  2979.         }
  2980.  
  2981.         Window -> UserPort = NULL;
  2982.     }
  2983.  
  2984.     ModifyIDCMP(Window,NULL);
  2985.  
  2986.     Permit();
  2987.  
  2988.     LT_DeleteWindowLock(Window);
  2989.  
  2990.     CloseWindow(Window);
  2991. }
  2992.  
  2993.     /* WaitTime(LONG Secs,LONG Micros):
  2994.      *
  2995.      *    Wait a given period of time.
  2996.      */
  2997.  
  2998. VOID __regargs
  2999. WaitTime(LONG Secs,LONG Micros)
  3000. {
  3001.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  3002.     TimeRequest -> tr_time . tv_secs    = Secs;
  3003.     TimeRequest -> tr_time . tv_micro    = Micros;
  3004.  
  3005.     DoIO(TimeRequest);
  3006. }
  3007.  
  3008.     /* StopTime():
  3009.      *
  3010.      *    Stop the running timer.
  3011.      */
  3012.  
  3013. VOID
  3014. StopTime()
  3015. {
  3016.     if(TimerRunning)
  3017.     {
  3018.         if(!CheckIO(TimeRequest))
  3019.             AbortIO(TimeRequest);
  3020.  
  3021.         WaitIO(TimeRequest);
  3022.     }
  3023. }
  3024.  
  3025.     /* StartTime(LONG Secs,LONG Micros):
  3026.      *
  3027.      *    Start the timer asynchronously.
  3028.      */
  3029.  
  3030. VOID __regargs
  3031. StartTime(LONG Secs,LONG Micros)
  3032. {
  3033.     StopTime();
  3034.  
  3035.     TimeRequest -> tr_node . io_Command    = TR_ADDREQUEST;
  3036.     TimeRequest -> tr_time . tv_secs    = Secs;
  3037.     TimeRequest -> tr_time . tv_micro    = Micros;
  3038.  
  3039.     ClrSignal(SIG_TIMER);
  3040.  
  3041.     SendIO(TimeRequest);
  3042.  
  3043.     TimerRunning = TRUE;
  3044. }
  3045.  
  3046.     /* GetEnvDOS(STRPTR Name,STRPTR Buffer):
  3047.      *
  3048.      *    Get the contents of a vanilla AmigaDOS environment
  3049.      *    variable.
  3050.      */
  3051.  
  3052. STRPTR __regargs
  3053. GetEnvDOS(STRPTR Name,STRPTR Buffer)
  3054. {
  3055.     LONG    Size;
  3056.     BPTR    File,SomeLock;
  3057.  
  3058.     Buffer[0] = 0;
  3059.  
  3060.         /* Is ENV: present? */
  3061.  
  3062.     if(SomeLock = Lock("Env:",ACCESS_READ))
  3063.     {
  3064.         UBYTE SomeBuffer[MAX_FILENAME_LENGTH];
  3065.  
  3066.         UnLock(SomeLock);
  3067.  
  3068.         strcpy(SomeBuffer,"Env:");
  3069.         strcat(SomeBuffer,Name);
  3070.  
  3071.             /* Open the file. */
  3072.  
  3073.         if(File = Open(SomeBuffer,MODE_OLDFILE))
  3074.         {
  3075.                 /* Read the contents. */
  3076.  
  3077.             Size = Read(File,Buffer,256);
  3078.  
  3079.             Close(File);
  3080.  
  3081.             if(Size > 0)
  3082.             {
  3083.                 Buffer[Size] = 0;
  3084.  
  3085.                 return(Buffer);
  3086.             }
  3087.         }
  3088.     }
  3089.  
  3090.     return(NULL);
  3091. }
  3092.  
  3093.     /* SetEnvDOS(STRPTR Name,STRPTR Value):
  3094.      *
  3095.      *    Set the contents of a vanilla AmigaDOS environment
  3096.      *    variable.
  3097.      */
  3098.  
  3099. BYTE __regargs
  3100. SetEnvDOS(STRPTR Name,STRPTR Value)
  3101. {
  3102.     UBYTE    Buffer[MAX_FILENAME_LENGTH],*Destination;
  3103.     LONG    Length;
  3104.     BPTR    File,FileLock;
  3105.     BYTE    Success = TRUE;
  3106.     WORD    i;
  3107.  
  3108.     for(i = 0 ; i < 2 ; i++)
  3109.     {
  3110.         if(i)
  3111.             Destination = "EnvArc:";
  3112.         else
  3113.             Destination = "Env:";
  3114.  
  3115.             /* Is ENV:/ENVARC: present? */
  3116.  
  3117.         if(FileLock = Lock(Destination,ACCESS_READ))
  3118.         {
  3119.             UnLock(FileLock);
  3120.  
  3121.             strcpy(Buffer,Destination);
  3122.             strcat(Buffer,Name);
  3123.  
  3124.                 /* There already is a variable of that
  3125.                  * name in the environment storage
  3126.                  * directory.
  3127.                  */
  3128.  
  3129.             if(FileLock = Lock(Buffer,ACCESS_WRITE))
  3130.             {
  3131.                 UnLock(FileLock);
  3132.  
  3133.                     /* Delete the variable. */
  3134.  
  3135.                 if(!DeleteFile(Buffer))
  3136.                 {
  3137.                     Success = FALSE;
  3138.  
  3139.                     continue;
  3140.                 }
  3141.             }
  3142.  
  3143.                 /* Set the new variable. */
  3144.  
  3145.             if(Length = strlen(Value))
  3146.             {
  3147.                 if(File = Open(Buffer,MODE_NEWFILE))
  3148.                 {
  3149.                     if(Write(File,Value,Length) != Length)
  3150.                     {
  3151.                         Close(File);
  3152.  
  3153.                         DeleteFile(Buffer);
  3154.  
  3155.                         Success = FALSE;
  3156.                     }
  3157.                     else
  3158.                     {
  3159.                         Close(File);
  3160.  
  3161.                         AddProtection(Buffer,FIBF_EXECUTE);
  3162.                     }
  3163.                 }
  3164.                 else
  3165.                     Success = FALSE;
  3166.             }
  3167.         }
  3168.         else
  3169.             Success = FALSE;
  3170.     }
  3171.  
  3172.     return(Success);
  3173. }
  3174.  
  3175.     /* BumpWindow(struct Window *SomeWindow):
  3176.      *
  3177.      *    Bring a window to the front (and shift the screen
  3178.      *    back to its initial position).
  3179.      */
  3180.  
  3181. VOID __regargs
  3182. BumpWindow(struct Window *SomeWindow)
  3183. {
  3184.     if(SomeWindow)
  3185.     {
  3186.         if(SomeWindow -> WScreen -> LeftEdge > 0)
  3187.         {
  3188.             if(SomeWindow -> WScreen -> TopEdge > 0)
  3189.                 MoveScreen(SomeWindow -> WScreen,-SomeWindow -> WScreen -> LeftEdge,-SomeWindow -> WScreen -> TopEdge);
  3190.             else
  3191.                 MoveScreen(SomeWindow -> WScreen,-SomeWindow -> WScreen -> LeftEdge,0);
  3192.         }
  3193.         else
  3194.         {
  3195.             if(SomeWindow -> WScreen -> TopEdge > 0)
  3196.                 MoveScreen(SomeWindow -> WScreen,0,-SomeWindow -> WScreen -> TopEdge);
  3197.         }
  3198.  
  3199.         ScreenToFront(SomeWindow -> WScreen);
  3200.  
  3201.         ActivateWindow(SomeWindow);
  3202.     }
  3203. }
  3204.  
  3205.     /* PushWindow(struct Window *Window):
  3206.      *
  3207.      *    Push/PopWindow implement a single lifo window stack
  3208.      *    which always updates the window to activate when
  3209.      *    LSHIFT+RSHIFT+RETURN is pressed. This routine will
  3210.      *    push a window on the stack.
  3211.      */
  3212.  
  3213. VOID __regargs
  3214. PushWindow(struct Window *Window)
  3215. {
  3216.     if(WindowStackPtr < 5)
  3217.     {
  3218.         WindowStack[WindowStackPtr++] = Window;
  3219.  
  3220.         TopWindow = Window;
  3221.     }
  3222. }
  3223.  
  3224.     /* PopWindow():
  3225.      *
  3226.      *    Remove topmost window from window stack.
  3227.      */
  3228.  
  3229. VOID
  3230. PopWindow()
  3231. {
  3232.     if(WindowStackPtr > 0)
  3233.     {
  3234.         WindowStackPtr--;
  3235.  
  3236.         if(WindowStackPtr)
  3237.             TopWindow = WindowStack[WindowStackPtr - 1];
  3238.         else
  3239.             TopWindow = Window;
  3240.     }
  3241. }
  3242.  
  3243.     /* LoadMacros(STRPTR Name,struct MacroKeys *Keys):
  3244.      *
  3245.      *    Load the keyboard macros from a file.
  3246.      */
  3247.  
  3248. BYTE __regargs
  3249. LoadMacros(STRPTR Name,struct MacroKeys *Keys)
  3250. {
  3251.     struct IFFHandle    *Handle;
  3252.     BYTE             Success = FALSE;
  3253.     struct StoredProperty    *Prop;
  3254.     struct TermInfo        *TermInfo;
  3255.     LONG             Error;
  3256.  
  3257.     if(Handle = AllocIFF())
  3258.     {
  3259.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  3260.         {
  3261.             InitIFFasDOS(Handle);
  3262.  
  3263.             if(!(Error = OpenIFF(Handle,IFFF_READ)))
  3264.             {
  3265.                 /* Collect version number ID if
  3266.                  * available.
  3267.                  */
  3268.  
  3269.                 if(!(Error = PropChunks(Handle,(LONG *)VersionProps,1)))
  3270.                 {
  3271.                     /* The following line tells iffparse to stop at the
  3272.                      * very beginning of a `Type' chunk contained in a
  3273.                      * `TERM' FORM chunk.
  3274.                      */
  3275.  
  3276.                     if(!(Error = StopChunk(Handle,ID_TERM,ID_KEYS)))
  3277.                     {
  3278.                         /* Parse the file... */
  3279.  
  3280.                         if(!ParseIFF(Handle,IFFPARSE_SCAN))
  3281.                         {
  3282.                             /* Did we get a version ID? */
  3283.  
  3284.                             if(Prop = FindProp(Handle,ID_TERM,ID_VERS))
  3285.                             {
  3286.                                 TermInfo = (struct TermInfo *)Prop -> sp_Data;
  3287.  
  3288.                                 /* Is it the file format we are able
  3289.                                  * to read?
  3290.                                  */
  3291.  
  3292.                                 if((TermInfo -> Version > CONFIG_FILE_VERSION) || (TermInfo -> Version == CONFIG_FILE_VERSION && TermInfo -> Revision > CONFIG_FILE_REVISION) || (TermInfo -> Version == 1 && TermInfo -> Revision < 6))
  3293.                                 {
  3294.                                         /* Probably an older revision. */
  3295.  
  3296.                                     if(TermInfo -> Version == 1 && TermInfo -> Revision < 6)
  3297.                                     {
  3298.                                         memset(Keys,0,sizeof(struct MacroKeys));
  3299.  
  3300.                                         if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
  3301.                                             Success = TRUE;
  3302.                                         else
  3303.                                             Error = IoErr();
  3304.                                     }
  3305.                                     else
  3306.                                         Error = ERR_OUTDATED;
  3307.                                 }
  3308.                                 else
  3309.                                 {
  3310.                                     /* The file read pointer is positioned
  3311.                                      * just in front of the first data
  3312.                                      * to be read, so let's don't disappoint
  3313.                                      * iffparse and read it.
  3314.                                      */
  3315.  
  3316.                                     if(ReadChunkBytes(Handle,Keys,sizeof(struct MacroKeys)) == sizeof(struct MacroKeys))
  3317.                                         Success = TRUE;
  3318.                                     else
  3319.                                         Error = IoErr();
  3320.                                 }
  3321.                             }
  3322.                             else
  3323.                             {
  3324.                                     /* File was created by WriteIFFData previous
  3325.                                      * to revision 1.4.
  3326.                                      */
  3327.  
  3328.                                 memset(Keys,0,sizeof(struct MacroKeys));
  3329.  
  3330.                                 if(ReadChunkBytes(Handle,Keys,10 * 256) == 10 * 256)
  3331.                                     Success = TRUE;
  3332.                                 else
  3333.                                     Error = IoErr();
  3334.                             }
  3335.                         }
  3336.                     }
  3337.                 }
  3338.  
  3339.                 CloseIFF(Handle);
  3340.             }
  3341.  
  3342.             Close(Handle -> iff_Stream);
  3343.         }
  3344.         else
  3345.             Error = IoErr();
  3346.  
  3347.         FreeIFF(Handle);
  3348.     }
  3349.     else
  3350.         Error = ERR_NO_MEM;
  3351.  
  3352.     if(Error)
  3353.         SetIoErr(Error);
  3354.  
  3355.     return(Success);
  3356. }
  3357.  
  3358.     /* WriteIFFData(STRPTR Name,APTR Data,LONG Size,ULONG Type):
  3359.      *
  3360.      *    Write data to an IFF file (via iffparse.library).
  3361.      */
  3362.  
  3363. BYTE __regargs
  3364. WriteIFFData(STRPTR Name,APTR Data,LONG Size,ULONG Type)
  3365. {
  3366.     struct IFFHandle    *Handle;
  3367.     BYTE             Success = FALSE;
  3368.     LONG             Error;
  3369.  
  3370.         /* Allocate a handle. */
  3371.  
  3372.     if(Handle = AllocIFF())
  3373.     {
  3374.             /* Open an output stream. */
  3375.  
  3376.         if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
  3377.         {
  3378.                 /* Tell iffparse that this is
  3379.                  * a DOS handle.
  3380.                  */
  3381.  
  3382.             InitIFFasDOS(Handle);
  3383.  
  3384.                 /* Open the handle for writing. */
  3385.  
  3386.             if(!(Error = OpenIFF(Handle,IFFF_WRITE)))
  3387.             {
  3388.                     /* Push outmost chunk onto stack. */
  3389.  
  3390.                 if(!(Error = PushChunk(Handle,ID_TERM,ID_FORM,IFFSIZE_UNKNOWN)))
  3391.                 {
  3392.                         /* Add a version identifier. */
  3393.  
  3394.                     if(!(Error = PushChunk(Handle,0,ID_VERS,IFFSIZE_UNKNOWN)))
  3395.                     {
  3396.                         struct TermInfo TermInfo;
  3397.  
  3398.                         TermInfo . Version    = CONFIG_FILE_VERSION;
  3399.                         TermInfo . Revision    = CONFIG_FILE_REVISION;
  3400.  
  3401.                             /* Write the version data. */
  3402.  
  3403.                         if(WriteChunkBytes(Handle,&TermInfo,sizeof(struct TermInfo)) == sizeof(struct TermInfo))
  3404.                         {
  3405.                                 /* Pop the version chunk, i.e. write it to the file. */
  3406.  
  3407.                             if(Error = PopChunk(Handle))
  3408.                                 Success = FALSE;
  3409.                             else
  3410.                             {
  3411.                                     /* Push the real data chunk on the stack. */
  3412.  
  3413.                                 if(!(Error = PushChunk(Handle,0,Type,IFFSIZE_UNKNOWN)))
  3414.                                 {
  3415.                                         /* Write the data. */
  3416.  
  3417.                                     if(WriteChunkBytes(Handle,Data,Size) == Size)
  3418.                                         Success = TRUE;
  3419.                                     else
  3420.                                         Error = IoErr();
  3421.  
  3422.                                             /* Pop the data chunk. */
  3423.  
  3424.                                     if(Success)
  3425.                                     {
  3426.                                         if(Error = PopChunk(Handle))
  3427.                                             Success = FALSE;
  3428.                                     }
  3429.                                 }
  3430.                                 else
  3431.                                     Success = FALSE;
  3432.                             }
  3433.                         }
  3434.                         else
  3435.                         {
  3436.                             Error = IoErr();
  3437.  
  3438.                             Success = FALSE;
  3439.                         }
  3440.                     }
  3441.  
  3442.                         /* Seems that we're done, now try to pop the FORM chunk
  3443.                          * and return.
  3444.                          */
  3445.  
  3446.                     if(Success)
  3447.                     {
  3448.                         if(Error = PopChunk(Handle))
  3449.                             Success = FALSE;
  3450.                     }
  3451.                 }
  3452.  
  3453.                     /* Close the handle (flush any pending data). */
  3454.  
  3455.                 CloseIFF(Handle);
  3456.             }
  3457.  
  3458.                 /* Close the DOS handle itself. */
  3459.  
  3460.             Close(Handle -> iff_Stream);
  3461.         }
  3462.         else
  3463.             Error = IoErr();
  3464.  
  3465.             /* And free the IFF handle. */
  3466.  
  3467.         FreeIFF(Handle);
  3468.     }
  3469.     else
  3470.         Error = ERR_NO_MEM;
  3471.  
  3472.     if(Success)
  3473.         AddProtection(Name,FIBF_EXECUTE);
  3474.  
  3475.     if(Error)
  3476.         SetIoErr(Error);
  3477.  
  3478.     return(Success);
  3479. }
  3480.  
  3481.     /* ReadIFFData(STRPTR Name,APTR Data,LONG Size,ULONG Type):
  3482.      *
  3483.      *    Read data from a `TERM' FORM chunk contained in an IFF file.
  3484.      */
  3485.  
  3486. BYTE __regargs
  3487. ReadIFFData(STRPTR Name,APTR Data,LONG Size,ULONG Type)
  3488. {
  3489.     struct IFFHandle    *Handle;
  3490.     BYTE             Success = FALSE;
  3491.     struct StoredProperty    *Prop;
  3492.     struct TermInfo        *TermInfo;
  3493.     LONG             Error = 0;
  3494.  
  3495.     if(Handle = AllocIFF())
  3496.     {
  3497.         if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
  3498.         {
  3499.             InitIFFasDOS(Handle);
  3500.  
  3501.             if(!(Error = OpenIFF(Handle,IFFF_READ)))
  3502.             {
  3503.                 /* Collect version number ID if
  3504.                  * available.
  3505.                  */
  3506.  
  3507.                 if(!(Error = PropChunks(Handle,(LONG *)VersionProps,1)))
  3508.                 {
  3509.                     /* The following line tells iffparse to stop at the
  3510.                      * very beginning of a `Type' chunk contained in a
  3511.                      * `TERM' FORM chunk.
  3512.                      */
  3513.  
  3514.                     if(!(Error = StopChunk(Handle,ID_TERM,Type)))
  3515.                     {
  3516.                         /* Parse the file... */
  3517.  
  3518.                         if(!ParseIFF(Handle,IFFPARSE_SCAN))
  3519.                         {
  3520.                             /* Did we get a version ID? */
  3521.  
  3522.                             if(Prop = FindProp(Handle,ID_TERM,ID_VERS))
  3523.                             {
  3524.                                 TermInfo = (struct TermInfo *)Prop -> sp_Data;
  3525.  
  3526.                                 /* Is it the file format we are able
  3527.                                  * to read?
  3528.                                  */
  3529.  
  3530.                                 if((TermInfo -> Version > CONFIG_FILE_VERSION) || (TermInfo -> Version == CONFIG_FILE_VERSION && TermInfo -> Revision > CONFIG_FILE_REVISION) || (TermInfo -> Version == 1 && TermInfo -> Revision < 6))
  3531.                                 {
  3532.                                     Error = ERR_OUTDATED;
  3533.  
  3534.                                     Success = FALSE;
  3535.                                 }
  3536.                                 else
  3537.                                 {
  3538.                                     struct ContextNode *Chunk = CurrentChunk(Handle);
  3539.  
  3540.                                     if(Chunk -> cn_Size < Size)
  3541.                                         Size = Chunk -> cn_Size;
  3542.  
  3543.                                     /* The file read pointer is positioned
  3544.                                      * just in front of the first data
  3545.                                      * to be read, so let's don't disappoint
  3546.                                      * iffparse and read it.
  3547.                                      */
  3548.  
  3549.                                     if(ReadChunkBytes(Handle,Data,Size) == Size)
  3550.                                         Success = TRUE;
  3551.                                     else
  3552.                                         Error = IoErr();
  3553.                                 }
  3554.                             }
  3555.                         }
  3556.                     }
  3557.                 }
  3558.  
  3559.                 CloseIFF(Handle);
  3560.             }
  3561.  
  3562.             Close(Handle -> iff_Stream);
  3563.         }
  3564.         else
  3565.             Error = IoErr();
  3566.  
  3567.         FreeIFF(Handle);
  3568.     }
  3569.  
  3570.     if(Error)
  3571.         SetIoErr(Error);
  3572.  
  3573.     return(Success);
  3574. }
  3575.  
  3576.     /* SplitFileName():
  3577.      *
  3578.      *    Split a full file name into a file and a drawer name.
  3579.      */
  3580.  
  3581. VOID __regargs
  3582. SplitFileName(STRPTR FullName,STRPTR *FileName,STRPTR DrawerName)
  3583. {
  3584.     if(FilePart(FullName) == FullName)
  3585.     {
  3586.         *DrawerName    = 0;
  3587.         *FileName    = FullName;
  3588.     }
  3589.     else
  3590.     {
  3591.         STRPTR Dummy;
  3592.  
  3593.         strcpy(DrawerName,FullName);
  3594.  
  3595.         Dummy = PathPart(DrawerName);
  3596.  
  3597.         *Dummy = 0;
  3598.  
  3599.         *FileName = FilePart(FullName);
  3600.     }
  3601. }
  3602.  
  3603.     /* CreateList():
  3604.      *
  3605.      *    Create a small, empty list.
  3606.      */
  3607.  
  3608. struct List *
  3609. CreateList()
  3610. {
  3611.     struct List *List = (struct List *)AllocVecPooled(sizeof(struct MinList),MEMF_ANY);
  3612.  
  3613.     if(List)
  3614.         NewList(List);
  3615.  
  3616.     return(List);
  3617. }
  3618.  
  3619.     /* DeleteList():
  3620.      *
  3621.      *    Free the contents of a list and the list itself.
  3622.      */
  3623.  
  3624. VOID __regargs
  3625. DeleteList(struct List *List)
  3626. {
  3627.     if(List)
  3628.     {
  3629.         struct Node    *Node,
  3630.                 *Next;
  3631.  
  3632.         for(Node = List -> lh_Head ; Next = Node -> ln_Succ ; Node = Next)
  3633.             FreeVecPooled(Node);
  3634.  
  3635.         FreeVecPooled(List);
  3636.     }
  3637. }
  3638.  
  3639.     /* BackfillRoutine():
  3640.      *
  3641.      *    Window layer backfill routine.
  3642.      */
  3643.  
  3644. VOID __asm __saveds
  3645. BackfillRoutine(register __a0 struct Hook *Hook,register __a1 struct {ULONG Layer; struct Rectangle Bounds;} *Bounds,register __a2 struct RastPort *RPort)
  3646. {
  3647.     BltBitMap(&BackfillBitMap,0,0,RPort->BitMap,Bounds->Bounds.MinX,Bounds->Bounds.MinY,Bounds->Bounds.MaxX - Bounds->Bounds.MinX + 1,Bounds->Bounds.MaxY - Bounds->Bounds.MinY + 1,0xC0,~0,NULL);
  3648. /*
  3649.     struct RastPort RastPort = *RPort;
  3650.  
  3651.     RPort = &RastPort;
  3652.  
  3653.     RPort -> Layer = NULL;
  3654.  
  3655.     if(Kick30)
  3656.         SetABPenDrMd(RPort,DrawInfo -> dri_Pens[BACKGROUNDPEN],0,JAM1);
  3657.     else
  3658.     {
  3659.         SetAPen(RPort,DrawInfo -> dri_Pens[BACKGROUNDPEN]);
  3660.         SetDrMd(RPort,JAM1);
  3661.     }
  3662.  
  3663.     RectFill(RPort,Bounds -> Bounds . MinX,Bounds -> Bounds . MinY,Bounds -> Bounds . MaxX,Bounds -> Bounds . MaxY);
  3664. */
  3665. }
  3666.  
  3667. struct NameSegment
  3668. {
  3669.     UBYTE    String[63],
  3670.         Separator;
  3671. };
  3672.  
  3673. STATIC UBYTE * __regargs
  3674. GetNameSegment(struct NameSegment *NameSegment,UBYTE *cp,WORD i)
  3675. {
  3676.     UBYTE *xp = NameSegment[i] . String;
  3677.  
  3678.     while (*cp && !strchr("._+-,@~=",*cp))
  3679.         *xp++ = *cp++;
  3680.  
  3681.     *xp = '\0';
  3682.  
  3683.     NameSegment[i] . Separator = *cp;
  3684.  
  3685.     if (*cp)
  3686.         cp++;
  3687.  
  3688.     if(NameSegment[i] . String[0] || NameSegment[i] . Separator)
  3689.         return(cp);
  3690.     else
  3691.         return(NULL);
  3692. }
  3693.  
  3694. STATIC VOID __regargs
  3695. CopyNameSegment(struct NameSegment *NameSegment,UBYTE *Destination,WORD Zap)
  3696. {
  3697.     UBYTE *cp = Destination,*xp;
  3698.  
  3699.     for(xp = NameSegment[0] . String ; *xp ; )
  3700.         *cp++ = *xp++;
  3701.  
  3702.     if(NameSegment[0] . Separator)
  3703.     {
  3704.         register WORD i;
  3705.  
  3706.         *cp++ = NameSegment[0] . Separator;
  3707.  
  3708.         for(i = Zap + 1 ; ; i++)
  3709.         {
  3710.             for(xp = NameSegment[i] . String ; *xp ; )
  3711.                 *cp++ = *xp++;
  3712.  
  3713.             if(NameSegment[i] . Separator)
  3714.                 *cp++ = NameSegment[i] . Separator;
  3715.             else
  3716.             {
  3717.                 if(!NameSegment[i] . String[0])
  3718.                     break;
  3719.             }
  3720.         }
  3721.     }
  3722.  
  3723.     *cp = 0;
  3724. }
  3725.  
  3726.     /* ShrinkName():
  3727.      *
  3728.      *    Shrink a file name down to a number of characters, if
  3729.      *    possible preserving the structure of the name. Algorithm
  3730.      *    courtesy of the "shrink" program by Simon Brown,
  3731.      *    Edinburgh University.
  3732.      */
  3733.  
  3734. UBYTE * __regargs
  3735. ShrinkName(const UBYTE *Source,UBYTE *Destination,WORD MaxLength,BOOLEAN FixSuffix)
  3736. {
  3737.     #define MAXSEGS 10
  3738.  
  3739.     struct NameSegment NameSegment[MAXSEGS];
  3740.  
  3741.     WORD i,NumSegments,SuffixLength,Remainder,Delete,Total,Zap = 0;
  3742.     UBYTE *OldPtr = (UBYTE *)Source;
  3743.  
  3744.     for(i = 0 ; i < MAXSEGS && (OldPtr = GetNameSegment(NameSegment,OldPtr,i)) ; i++);
  3745.  
  3746.     if(i < MAXSEGS)
  3747.     {
  3748.         NumSegments = i - 1;
  3749.  
  3750.         if((NumSegments * 2) < MaxLength)
  3751.         {
  3752.             SuffixLength = strlen(NameSegment[NumSegments] . String);
  3753.  
  3754.             if(SuffixLength > MaxLength - NumSegments - 1)
  3755.             {
  3756.                 SuffixLength = MaxLength - (2 * NumSegments) - 1;
  3757.  
  3758.                 NameSegment[NumSegments] . String[SuffixLength - 1] = 0;
  3759.             }
  3760.             else
  3761.             {
  3762.                 if (SuffixLength + NumSegments > MaxLength-NumSegments-1)
  3763.                     Zap = NumSegments - (MaxLength-SuffixLength)/2;
  3764.             }
  3765.  
  3766.             if(NumSegments >= 1)
  3767.             {
  3768.                 for(i = Zap + 1 ; i <= NumSegments ; i++)
  3769.                 {
  3770.                     if(NameSegment[i] . Separator)
  3771.                         SuffixLength++;
  3772.                 }
  3773.  
  3774.                 if(NameSegment[0] . Separator)
  3775.                     SuffixLength++;
  3776.  
  3777.                 Remainder = MaxLength - SuffixLength;
  3778.  
  3779.                 Delete = Remainder / NumSegments;
  3780.  
  3781.                 Total = SuffixLength;
  3782.  
  3783.                 for(i = Zap + 1 ; i < NumSegments ; i++)
  3784.                 {
  3785.                     NameSegment[i] . String[Delete] = 0;
  3786.  
  3787.                     Total += Delete;
  3788.                 }
  3789.  
  3790.                 NameSegment[0] . String[MaxLength - Total] = 0;
  3791.             }
  3792.  
  3793.             CopyNameSegment(NameSegment,Destination,Zap);
  3794.         }
  3795.         else
  3796.             strcpy(Destination,Source);
  3797.     }
  3798.     else
  3799.         strcpy(Destination,Source);
  3800.  
  3801.     if(FixSuffix)
  3802.     {
  3803.         BOOLEAN    GotDot    = FALSE;
  3804.         LONG    Len    = strlen(Destination),Dots;
  3805.  
  3806.         for(i = Dots = 0 ; i < Len ; i++)
  3807.         {
  3808.             if(Destination[i] == '.')
  3809.                 Dots++;
  3810.         }
  3811.  
  3812.         if(!Dots)
  3813.         {
  3814.             if(Len < 4)
  3815.                 strcat(Destination,".___");
  3816.             else
  3817.                 Destination[Len - 4] = '.';
  3818.         }
  3819.  
  3820.         for(i = Len - 1 ; i >= 0 ; i--)
  3821.         {
  3822.             if(Destination[i] == '.')
  3823.             {
  3824.                 if(GotDot)
  3825.                     Destination[i] = '_';
  3826.                 else
  3827.                     GotDot = TRUE;
  3828.             }
  3829.  
  3830.             if(Destination[i] == '\\')
  3831.                 Destination[i] = '-';
  3832.         }
  3833.     }
  3834.  
  3835.     return(Destination);
  3836. }
  3837.  
  3838.     /* BuildFontName(STRPTR Destination,const STRPTR Name,LONG Size):
  3839.      *
  3840.      *    Build a font name and size string from given
  3841.      *    information (raw name and size).
  3842.      */
  3843.  
  3844. VOID __regargs
  3845. BuildFontName(STRPTR Destination,const STRPTR Name,LONG Size)
  3846. {
  3847.     UBYTE    LocalBuffer[50];
  3848.     LONG    Len;
  3849.  
  3850.     strcpy(LocalBuffer,FilePart((STRPTR)Name));
  3851.  
  3852.     Len = strlen(LocalBuffer);
  3853.  
  3854.     if(Len > 5)
  3855.     {
  3856.         if(!Stricmp(&LocalBuffer[Len - 5],".font"))
  3857.             LocalBuffer[Len - 5] = 0;
  3858.     }
  3859.  
  3860.     SPrintf(Destination,"%s %ld",LocalBuffer,Size);
  3861. }
  3862.  
  3863.     /* CreateMenuGlyphs():
  3864.      *
  3865.      *    Create scaled glyphs for pull-down menus.
  3866.      */
  3867.  
  3868. BOOLEAN __regargs
  3869. CreateMenuGlyphs(struct Screen *Screen,struct DrawInfo *DrawInfo,struct Image **AmigaPtr,struct Image **CheckPtr)
  3870. {
  3871.     struct Image    *AmigaGlyph,
  3872.             *CheckGlyph;
  3873.     LONG         AspectX,AspectY,
  3874.              Size,FontHeight;
  3875.  
  3876.     FontHeight = DrawInfo -> dri_Font -> tf_Baseline + 2;
  3877.  
  3878.     if(Screen -> Flags & SCREENHIRES)
  3879.         Size = SYSISIZE_MEDRES;
  3880.     else
  3881.         Size = SYSISIZE_LOWRES;
  3882.  
  3883.     AspectX = DrawInfo -> dri_Resolution . X;
  3884.     AspectY = DrawInfo -> dri_Resolution . Y;
  3885.  
  3886.     if(AmigaGlyph = NewObject(NULL,SYSICLASS,
  3887.         SYSIA_DrawInfo,    DrawInfo,
  3888.         SYSIA_Size,    Size,
  3889.         SYSIA_Which,    AMIGAKEY,
  3890.         IA_Left,    0,
  3891.         LA_Top,        0,
  3892.         IA_Width,    (FontHeight * 3 * AspectY) / (2 * AspectX),
  3893.         IA_Height,    FontHeight,
  3894.     TAG_DONE))
  3895.     {
  3896.         if(!(CheckGlyph = NewObject(NULL,SYSICLASS,
  3897.             SYSIA_DrawInfo,    DrawInfo,
  3898.             SYSIA_Size,    Size,
  3899.             SYSIA_Which,    MENUCHECK,
  3900.             IA_Left,    0,
  3901.             LA_Top,        0,
  3902.             IA_Width,    (FontHeight * AspectY) / AspectX,
  3903.             IA_Height,    FontHeight,
  3904.         TAG_DONE)))
  3905.         {
  3906.             DisposeObject(AmigaGlyph);
  3907.  
  3908.             AmigaGlyph = NULL;
  3909.         }
  3910.     }
  3911.  
  3912.     if(AmigaGlyph && CheckGlyph)
  3913.     {
  3914.         *AmigaPtr = AmigaGlyph;
  3915.         *CheckPtr = CheckGlyph;
  3916.  
  3917.         return(TRUE);
  3918.     }
  3919.     else
  3920.         return(FALSE);
  3921. }
  3922.  
  3923.     /* FixName(STRPTR Name):
  3924.      *
  3925.      *    Build a correct AmigaDOS filename.
  3926.      */
  3927.  
  3928. VOID __regargs
  3929. FixName(STRPTR Name)
  3930. {
  3931.     WORD    NameLen    = strlen(Name),
  3932.         i;
  3933.  
  3934.         /* Replace special characters. */
  3935.  
  3936.     for(i = 0 ; i < NameLen ; i++)
  3937.     {
  3938.         switch(Name[i])
  3939.         {
  3940.             case ' ':
  3941.  
  3942.                 Name[i] = '_';
  3943.                 break;
  3944.  
  3945.             case ':':
  3946.  
  3947.                 Name[i] = '.';
  3948.                 break;
  3949.  
  3950.             case '/':
  3951.  
  3952.                 Name[i] = '\\';
  3953.                 break;
  3954.  
  3955.             case '\"':
  3956.  
  3957.                 Name[i] = '\'';
  3958.                 break;
  3959.         }
  3960.     }
  3961.  
  3962.         /* Truncate the name. */
  3963.  
  3964.     if(NameLen > 31)
  3965.         Name[31] = 0;
  3966. }
  3967.  
  3968.     /* ShowError(struct Window *Window,LONG Primary,LONG Secondary,STRPTR String):
  3969.      *
  3970.      *    Display an error message, in human readable form if possible.
  3971.      */
  3972.  
  3973. VOID __regargs
  3974. ShowError(struct Window *Window,LONG Primary,LONG Secondary,STRPTR String)
  3975. {
  3976.     STATIC LONG LocalErrors[][2] =
  3977.     {
  3978.         ERR_SAVE_ERROR,            MSG_ERR_COULD_NOT_SAVE_FILE_TXT,
  3979.         ERR_LOAD_ERROR,            MSG_ERR_COULD_NOT_LOAD_FILE_TXT,
  3980.         ERR_NO_MEM,            MSG_ERR_NO_MEM_TXT,
  3981.         ERR_OUTDATED,            MSG_ERR_OUTDATED_TXT,
  3982.         ERR_EXECUTE_ERROR,        MSG_ERR_COULD_NOT_EXECUTE_PROGRAM_TXT,
  3983.  
  3984.         ERR_FILE_NOT_FOUND,        MSG_VERIFY_NO_FILE_TXT,
  3985.         ERR_DRAWER_NOT_FOUND,        MSG_VERIFY_DRAWER_NOT_FOUND_TXT,
  3986.         ERR_PROGRAM_NOT_FOUND,        MSG_VERIFY_NO_PROGRAM_TXT,
  3987.         ERR_NOT_A_FILE,            MSG_VERIFY_DRAWER_NOT_A_FILE_TXT,
  3988.         ERR_NOT_A_DRAWER,        MSG_VERIFY_FILE_NOT_A_DRAWER_TXT,
  3989.  
  3990.         IFFERR_NOMEM,            MSG_IFFERR_NOMEM_TXT,
  3991.         IFFERR_READ,            MSG_IFFERR_READ_TXT,
  3992.         IFFERR_WRITE,            MSG_IFFERR_WRITE_TXT,
  3993.         IFFERR_SEEK,            MSG_IFFERR_SEEK_TXT,
  3994.         IFFERR_MANGLED,            MSG_IFFERR_MANGLED_TXT,
  3995.         IFFERR_NOTIFF,            MSG_IFFERR_NOTIFF_TXT,
  3996.  
  3997.         0,                0
  3998.     };
  3999.  
  4000.     STRPTR    PrimaryError    = NULL,
  4001.         SecondaryError    = NULL;
  4002.  
  4003.     if(Primary)
  4004.     {
  4005.         LONG i;
  4006.  
  4007.         for(i = 0 ; LocalErrors[i][0] ; i++)
  4008.         {
  4009.             if(LocalErrors[i][0] == Primary)
  4010.             {
  4011.                 PrimaryError = LocaleString(LocalErrors[i][1]);
  4012.  
  4013.                 break;
  4014.             }
  4015.         }
  4016.  
  4017.         if(!PrimaryError)
  4018.         {
  4019.             STATIC UBYTE __far Buffer[256];
  4020.  
  4021.             Fault(Primary,"",Buffer,256);
  4022.  
  4023.             PrimaryError = Buffer + 2;
  4024.         }
  4025.     }
  4026.  
  4027.     if(Secondary)
  4028.     {
  4029.         LONG i;
  4030.  
  4031.         for(i = 0 ; LocalErrors[i][0] ; i++)
  4032.         {
  4033.             if(LocalErrors[i][0] == Secondary)
  4034.             {
  4035.                 SecondaryError = LocaleString(LocalErrors[i][1]);
  4036.  
  4037.                 break;
  4038.             }
  4039.         }
  4040.  
  4041.         if(!SecondaryError)
  4042.         {
  4043.             STATIC UBYTE __far Buffer[256];
  4044.  
  4045.             Fault(Secondary,"",Buffer,256);
  4046.  
  4047.             SecondaryError = Buffer + 2;
  4048.         }
  4049.     }
  4050.  
  4051.     if(PrimaryError)
  4052.     {
  4053.         if(String)
  4054.             MyEasyRequest(Window,PrimaryError,LocaleString(MSG_GLOBAL_CONTINUE_TXT),String,SecondaryError);
  4055.         else
  4056.             MyEasyRequest(Window,PrimaryError,LocaleString(MSG_GLOBAL_CONTINUE_TXT),SecondaryError);
  4057.     }
  4058. }
  4059.  
  4060. struct RendezvousData * __saveds __asm
  4061. RendezvousLogin(register __a0 struct MsgPort *ReadPort,register __a1 struct MsgPort *WritePort,register __a2 struct TagItem *TagList)
  4062. {
  4063.     struct RendezvousData *Data;
  4064.  
  4065.     if(Data = (struct RendezvousData *)AllocVecPooled(sizeof(struct RendezvousData),MEMF_ANY | MEMF_CLEAR))
  4066.     {
  4067.         struct DataMsg Msg;
  4068.  
  4069.         InitMsgItem(&Msg,TaskDestructor);
  4070.  
  4071.         Msg . Type = DATAMSGTYPE_RENDEZVOUS;
  4072.         Msg . Data = (UBYTE *)SysBase -> ThisTask;
  4073.  
  4074.         Forbid();
  4075.  
  4076.         ClrSignal(SIGBREAKF_CTRL_F);
  4077.  
  4078.         PutMsgItem(SpecialQueue,(struct MsgItem *)&Msg);
  4079.  
  4080.         Wait(SIGBREAKF_CTRL_F);
  4081.  
  4082.         Permit();
  4083.  
  4084.         if(ReadRequest && WriteRequest)
  4085.         {
  4086.             struct List *UploadList;
  4087.  
  4088.             CopyMem(ReadRequest,&Data -> rd_ReadRequest,sizeof(struct IOExtSer));
  4089.  
  4090.             Data -> rd_ReadRequest . IOSer . io_Message . mn_ReplyPort = ReadPort;
  4091.  
  4092.             CopyMem(WriteRequest,&Data -> rd_WriteRequest,sizeof(struct IOExtSer));
  4093.  
  4094.             Data -> rd_WriteRequest . IOSer . io_Message . mn_ReplyPort = WritePort;
  4095.  
  4096.             if(Window)
  4097.                 Data -> rd_Screen = Window -> WScreen;
  4098.  
  4099.             NewList(&Data -> rd_UploadList);
  4100.             NewList(&Data -> rd_DownloadList);
  4101.             NewList(&Data -> rd_SentList);
  4102.             NewList(&Data -> rd_ReceivedList);
  4103.  
  4104.             if(UploadList = GetUploadList())
  4105.             {
  4106.                 struct Node *Node,*Next;
  4107.  
  4108.                 for(Node = UploadList -> lh_Head ; Next = Node -> ln_Succ ; Node = Next)
  4109.                     AddTail(&Data -> rd_UploadList,Node);
  4110.  
  4111.                 FreeVecPooled(UploadList);
  4112.             }
  4113.  
  4114.             Data -> rd_SendPath    = Config -> PathConfig -> BinaryUploadPath;
  4115.             Data -> rd_ReceivePath    = Config -> PathConfig -> BinaryDownloadPath;
  4116.             Data -> rd_Options    = "";
  4117.         }
  4118.         else
  4119.         {
  4120.             FreeVecPooled(Data);
  4121.  
  4122.             Data = NULL;
  4123.         }
  4124.     }
  4125.  
  4126.     return(Data);
  4127. }
  4128.  
  4129. VOID __saveds __asm
  4130. RendezvousLogoff(register __a0 struct RendezvousData *Data)
  4131. {
  4132.     if(Data)
  4133.     {
  4134.         struct Node *Node,*Next;
  4135.  
  4136.         for(Node = Data -> rd_UploadList . lh_Head ; Next = Node -> ln_Succ ; Node = Next)
  4137.             FreeVecPooled(Node);
  4138.  
  4139.         for(Node = Data -> rd_DownloadList . lh_Head ; Next = Node -> ln_Succ ; Node = Next)
  4140.             FreeVecPooled(Node);
  4141.  
  4142.         for(Node = Data -> rd_SentList . lh_Head ; Next = Node -> ln_Succ ; Node = Next)
  4143.             FreeVecPooled(Node);
  4144.  
  4145.         for(Node = Data -> rd_ReceivedList . lh_Head ; Next = Node -> ln_Succ ; Node = Next)
  4146.             FreeVecPooled(Node);
  4147.  
  4148.         FreeVecPooled(Data);
  4149.  
  4150.         Signal(ThisProcess,SIG_HANDSHAKE);
  4151.     }
  4152. }
  4153.  
  4154. struct Node * __saveds __asm
  4155. RendezvousNewNode(register __a0 STRPTR Name)
  4156. {
  4157.     if(Name)
  4158.     {
  4159.         LONG Len;
  4160.  
  4161.         if(Len = strlen(Name))
  4162.         {
  4163.             struct Node *Node;
  4164.  
  4165.             if(Node = (struct Node *)AllocVecPooled(sizeof(struct Node) + Len + 1,MEMF_ANY))
  4166.             {
  4167.                 memset(Node,0,sizeof(struct Node));
  4168.  
  4169.                 strcpy(Node -> ln_Name = (STRPTR)(Node + 1),Name);
  4170.  
  4171.                 return(Node);
  4172.             }
  4173.         }
  4174.     }
  4175.  
  4176.     return(NULL);
  4177. }
  4178.  
  4179. struct List * __regargs
  4180. BuildModeList(LONG *Index,ULONG DisplayMode,ULONG (* __asm ModeFilter)(register __a1 ULONG ID))
  4181. {
  4182.     struct List    *List;
  4183.     LONG         Count = 0;
  4184.  
  4185.     *Index = 0;
  4186.  
  4187.     if(List = (struct List *)AllocVecPooled(sizeof(struct List),MEMF_ANY))
  4188.     {
  4189.         struct DisplayInfo    DisplayInfo;
  4190.         ULONG            SomeMode = INVALID_ID;
  4191.  
  4192.         NewList(List);
  4193.  
  4194.         while((SomeMode = NextDisplayInfo(SomeMode)) != INVALID_ID)
  4195.         {
  4196.             if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,SomeMode))
  4197.             {
  4198.                 if((DisplayInfo . PropertyFlags & DIPF_IS_WB) && !DisplayInfo . NotAvailable)
  4199.                 {
  4200.                     STRPTR Name;
  4201.  
  4202.                     if(ModeFilter)
  4203.                     {
  4204.                         if(!(*ModeFilter)(SomeMode))
  4205.                             continue;
  4206.                     }
  4207.  
  4208.                     if(Name = GetModeName(SomeMode))
  4209.                     {
  4210.                         struct ModeNode    *ModeNode;
  4211.  
  4212.                         if(ModeNode = (struct ModeNode *)AllocVecPooled(sizeof(struct ModeNode) + strlen(Name) + 1,MEMF_ANY))
  4213.                         {
  4214.                             ModeNode -> VanillaNode . ln_Name = (STRPTR)(ModeNode + 1);
  4215.  
  4216.                             strcpy(ModeNode -> VanillaNode . ln_Name,Name);
  4217.  
  4218.                             ModeNode -> DisplayID = SomeMode;
  4219.  
  4220.                             AddTail(List,ModeNode);
  4221.  
  4222.                             Count++;
  4223.                         }
  4224.                     }
  4225.                 }
  4226.             }
  4227.         }
  4228.     }
  4229.  
  4230.     if(Count)
  4231.     {
  4232.         struct ModeNode    *Node,
  4233.                 *Next;
  4234.  
  4235.         for(Node = (struct ModeNode *)List -> lh_Head ; Node -> VanillaNode . ln_Succ ; Node = (struct ModeNode *)Node -> VanillaNode . ln_Succ)
  4236.         {
  4237.             if(!(Node -> DisplayID & MONITOR_ID_MASK))
  4238.             {
  4239.                 for(Next = (struct ModeNode *)List -> lh_Head ; Next -> VanillaNode . ln_Succ ; Next = (struct ModeNode *)Next -> VanillaNode . ln_Succ)
  4240.                 {
  4241.                     if((Node -> DisplayID & ~MONITOR_ID_MASK) == (Next -> DisplayID & ~MONITOR_ID_MASK) && Next != Node)
  4242.                         Node -> DisplayID = INVALID_ID;
  4243.                 }
  4244.             }
  4245.  
  4246.             for(Next = (struct ModeNode *)List -> lh_Head ; Next -> VanillaNode . ln_Succ ; Next = (struct ModeNode *)Next -> VanillaNode . ln_Succ)
  4247.             {
  4248.                 if(Node -> DisplayID == Next -> DisplayID && Next != Node)
  4249.                     Next -> DisplayID = INVALID_ID;
  4250.             }
  4251.         }
  4252.  
  4253.         for(Node = (struct ModeNode *)List -> lh_Head ; Next = (struct ModeNode *)Node -> VanillaNode . ln_Succ ; Node = Next)
  4254.         {
  4255.             if(Node -> DisplayID == INVALID_ID)
  4256.             {
  4257.                 Count--;
  4258.  
  4259.                 Remove(Node);
  4260.  
  4261.                 FreeVecPooled(Node);
  4262.             }
  4263.         }
  4264.     }
  4265.  
  4266.     if(Count)
  4267.     {
  4268.         struct ModeNode    *Node,
  4269.                 *Next;
  4270.  
  4271.         for(Count = 0, Node = (struct ModeNode *)List -> lh_Head ; Next = (struct ModeNode *)Node -> VanillaNode . ln_Succ ; Node = Next)
  4272.         {
  4273.             if(Node -> DisplayID == DisplayMode)
  4274.             {
  4275.                 *Index = Count;
  4276.  
  4277.                 break;
  4278.             }
  4279.         }
  4280.  
  4281.         return(List);
  4282.     }
  4283.     else
  4284.     {
  4285.         DeleteList(List);
  4286.  
  4287.         return(NULL);
  4288.     }
  4289. }
  4290.  
  4291.     /* IsAssign(STRPTR Name):
  4292.      *
  4293.      *    Does a name refer to an assignment?
  4294.      */
  4295.  
  4296. BOOLEAN __regargs
  4297. IsAssign(STRPTR Name)
  4298. {
  4299.     WORD NameLen    = strlen(Name) - 1;
  4300.     BOOLEAN Result    = FALSE;
  4301.  
  4302.         /* Does it end with a colon? */
  4303.  
  4304.     if(Name[NameLen] == ':')
  4305.     {
  4306.         struct DosList *DosList;
  4307.  
  4308.             /* Lock the list of assignments for reading. */
  4309.  
  4310.         DosList = AttemptLockDosList(LDF_ASSIGNS | LDF_READ);
  4311.  
  4312.             /* Make sure the v37 bug doesn't catch us. */
  4313.  
  4314.         if(((ULONG)DosList) > 1)
  4315.         {
  4316.             STRPTR AssignName;
  4317.  
  4318.                 /* Scan the list... */
  4319.  
  4320.             while(DosList = NextDosEntry(DosList,LDF_ASSIGNS))
  4321.             {
  4322.                     /* Convert the name from icky
  4323.                      * BCPL to `C' style string.
  4324.                      */
  4325.  
  4326.                 AssignName = (STRPTR)BADDR(DosList -> dol_Name);
  4327.  
  4328.                     /* Does the name length match? */
  4329.  
  4330.                 if(AssignName[0] == NameLen)
  4331.                 {
  4332.                         /* Does the name itself match? */
  4333.  
  4334.                     if(!Strnicmp(&AssignName[1],Name,NameLen))
  4335.                     {
  4336.                         Result = TRUE;
  4337.  
  4338.                         break;
  4339.                     }
  4340.                 }
  4341.             }
  4342.  
  4343.                 /* Unlock the list of assignments. */
  4344.  
  4345.             UnLockDosList(LDF_ASSIGNS | LDF_READ);
  4346.         }
  4347.     }
  4348.  
  4349.         /* Return the result. */
  4350.  
  4351.     return(Result);
  4352. }
  4353.  
  4354.     /* LockInAssign(BPTR TheLock,STRPTR TheAssignment):
  4355.      *
  4356.      *    Check if a file lock is part of an assignment.
  4357.      */
  4358.  
  4359. BOOLEAN __regargs
  4360. LockInAssign(BPTR TheLock,STRPTR TheAssignment)
  4361. {
  4362.     struct DevProc    *DevProc    = NULL;
  4363.     struct MsgPort    *FileSysTask    = GetFileSysTask();
  4364.     BOOLEAN         Result        = FALSE;
  4365.  
  4366.  
  4367.         /* Loop until all assignments are
  4368.          * processed.
  4369.          */
  4370.  
  4371.     do
  4372.     {
  4373.             /* Get the default filesystem task
  4374.              * in case we stumble upon NULL
  4375.              * directory locks.
  4376.              */
  4377.  
  4378.         if(DevProc = GetDeviceProc(TheAssignment,DevProc))
  4379.         {
  4380.                 /* Set the default filesystem task. */
  4381.  
  4382.             SetFileSysTask(DevProc -> dvp_Port);
  4383.  
  4384.                 /* Is the lock on the list? */
  4385.  
  4386.             if(SameLock(DevProc -> dvp_Lock,TheLock) == LOCK_SAME)
  4387.                 Result = TRUE;
  4388.         }
  4389.         else
  4390.             break;
  4391.     }
  4392.     while(DevProc && (DevProc -> dvp_Flags & DVPF_ASSIGN) && !Result);
  4393.  
  4394.         /* Reset the default filesystem task. */
  4395.  
  4396.     SetFileSysTask(FileSysTask);
  4397.  
  4398.         /* Free device process data. */
  4399.  
  4400.     if(DevProc)
  4401.         FreeDeviceProc(DevProc);
  4402.  
  4403.     return(Result);
  4404. }
  4405.  
  4406.     /* DeleteBitMap(struct BitMap *BitMap):
  4407.      *
  4408.      *    Delete a bitmap created by CreateBitMap().
  4409.      */
  4410.  
  4411. VOID __regargs
  4412. DeleteBitMap(struct BitMap *BitMap)
  4413. {
  4414.     WaitBlit();
  4415.  
  4416.     if(Kick30)
  4417.         FreeBitMap(BitMap);
  4418.     else
  4419.     {
  4420.         LONG i;
  4421.  
  4422.         for(i = 0 ; i < BitMap -> Depth ; i++)
  4423.         {
  4424.             if(BitMap -> Planes[i])
  4425.                 FreeVec(BitMap -> Planes[i]);
  4426.         }
  4427.  
  4428.         FreeVecPooled(BitMap);
  4429.     }
  4430. }
  4431.  
  4432.     /* CreateBitMap(ULONG Width,ULONG Height,ULONG Depth,ULONG Flags,struct BitMap *Friend):
  4433.      *
  4434.      *    Create a new bitmap with given properties.
  4435.      */
  4436.  
  4437. struct BitMap * __regargs
  4438. CreateBitMap(ULONG Width,ULONG Height,ULONG Depth,ULONG Flags,struct BitMap *Friend)
  4439. {
  4440.     if(Kick30)
  4441.         return(AllocBitMap(Width,Height,Depth,Flags,Friend));
  4442.     else
  4443.     {
  4444.         struct BitMap    *BitMap;
  4445.         LONG         Plus;
  4446.  
  4447.         if(Depth > 8)
  4448.             Plus = (Depth - 8) * sizeof(PLANEPTR);
  4449.         else
  4450.             Plus = 0;
  4451.  
  4452.         if(BitMap = (struct BitMap *)AllocVecPooled(sizeof(struct BitMap) + Plus,MEMF_CLEAR))
  4453.         {
  4454.             LONG i,PageSize;
  4455.  
  4456.             InitBitMap(BitMap,Depth,Width,Height);
  4457.  
  4458.             PageSize = BitMap -> BytesPerRow * BitMap -> Rows;
  4459.  
  4460.             for(i = 0 ; i < BitMap -> Depth ; i++)
  4461.             {
  4462.                 if(!(BitMap -> Planes[i] = (PLANEPTR)AllocVec(PageSize,MEMF_CHIP)))
  4463.                 {
  4464.                     LONG j;
  4465.  
  4466.                     for(j = 0 ; j < i ; j++)
  4467.                         FreeVec(BitMap -> Planes[j]);
  4468.  
  4469.                     FreeVecPooled(BitMap);
  4470.  
  4471.                     return(NULL);
  4472.                 }
  4473.             }
  4474.  
  4475.             if(Flags & BMF_CLEAR)
  4476.                 BltBitMap(BitMap,0,0,BitMap,0,0,Width,Height,0x00,(1 << Depth) - 1,NULL);
  4477.         }
  4478.  
  4479.         return(BitMap);
  4480.     }
  4481. }
  4482.  
  4483.     /* LaunchCommand(STRPTR Command):
  4484.      *
  4485.      *    Launch a command, try to figure out if it's an ARexx
  4486.      *    command, a plain batch file or a program and act
  4487.      *    accordingly.
  4488.      */
  4489.  
  4490. LONG __regargs
  4491. LaunchCommand(STRPTR Command)
  4492. {
  4493.     UBYTE    LocalBuffer[MAX_FILENAME_LENGTH];
  4494.     BPTR    Stream,
  4495.         OutputStream;
  4496.     APTR    OldConsoleTask    = ThisProcess -> pr_ConsoleTask;
  4497.     BOOL    IsScript    = FALSE,
  4498.         IsRexx        = FALSE;
  4499.     LONG    Result;
  4500.     BPTR    CommandFile;
  4501.     UBYTE    NameBuffer[MAX_FILENAME_LENGTH];
  4502.     BPTR    FileLock;
  4503.     STRPTR    OtherName;
  4504.     WORD    i;
  4505.  
  4506.         /* Chop off the arguments. */
  4507.  
  4508.     memcpy(NameBuffer,Command,MAX_FILENAME_LENGTH - 1);
  4509.  
  4510.     NameBuffer[MAX_FILENAME_LENGTH - 1] = 0;
  4511.  
  4512.     for(i = 0 ; i < MAX_FILENAME_LENGTH ; i++)
  4513.     {
  4514.         if(NameBuffer[i] == ' ')
  4515.         {
  4516.             NameBuffer[i] = 0;
  4517.             break;
  4518.         }
  4519.     }
  4520.  
  4521.         /* Now do something useful. Check if the command
  4522.          * could be an ARexx script.
  4523.          */
  4524.  
  4525.     if(CommandFile = Open(NameBuffer,MODE_OLDFILE))
  4526.     {
  4527.         LONG Len;
  4528.  
  4529.             /* 256 bytes may be not be enough, but then
  4530.              * we're only guessing.
  4531.              */
  4532.  
  4533.         if((Len = Read(CommandFile,LocalBuffer,MAX_FILENAME_LENGTH)) > 0)
  4534.         {
  4535.             register UBYTE    c;
  4536.             LONG        i;
  4537.  
  4538.             for(i = 0 ; i < Len - 1 ; i++)
  4539.             {
  4540.                 c = LocalBuffer[i];
  4541.  
  4542.                     /* Stop on invalid characters. */
  4543.  
  4544.                 if((c < ' ' && c != '\r' && c != '\n' && c != '\a') || (c >= 127 && c < 160))
  4545.                     break;
  4546.                 else
  4547.                 {
  4548.                         /* Looks like the typical
  4549.                          * introductory comment line.
  4550.                          */
  4551.  
  4552.                     if(c == '/' && LocalBuffer[i + 1] == '*')
  4553.                     {
  4554.                         IsRexx = TRUE;
  4555.                         break;
  4556.                     }
  4557.                 }
  4558.             }
  4559.         }
  4560.  
  4561.         Close(CommandFile);
  4562.     }
  4563.  
  4564.         /* Ok, second check. Does it have the script bit set? */
  4565.  
  4566.     if(FileLock = Lock(NameBuffer,ACCESS_READ))
  4567.     {
  4568.         struct FileInfoBlock __aligned FileInfo;
  4569.  
  4570.         if(Examine(FileLock,&FileInfo))
  4571.         {
  4572.             if(FileInfo . fib_Protection & FIBF_SCRIPT)
  4573.                 IsScript = TRUE;
  4574.         }
  4575.  
  4576.         UnLock(FileLock);
  4577.     }
  4578.  
  4579.         /* If it's an ARexx command, launch it. */
  4580.  
  4581.     if(IsRexx)
  4582.     {
  4583.         SendARexxCommand(Command,TRUE);
  4584.  
  4585.         return(0);
  4586.     }
  4587.  
  4588.         /* If it's a script command, prepend the "Execute "
  4589.          * command. It's not perfect but it should work.
  4590.          */
  4591.  
  4592.     if(IsScript)
  4593.     {
  4594.         if(OtherName = AllocVecPooled(strlen("Execute ") + strlen(Command) + 1,MEMF_ANY))
  4595.         {
  4596.             strcpy(OtherName,"Execute ");
  4597.             strcat(OtherName,Command);
  4598.  
  4599.             Command = OtherName;
  4600.         }
  4601.     }
  4602.     else
  4603.         OtherName = NULL;
  4604.  
  4605.     if(WindowName[0])
  4606.     {
  4607.         UBYTE LocalName[MAXPUBSCREENNAME + 1];
  4608.  
  4609.         if(Window)
  4610.         {
  4611.             if(!GetPubScreenName(Window -> WScreen,LocalName))
  4612.                 LocalName[0] = 0;
  4613.         }
  4614.  
  4615.         if(LocalName[0])
  4616.         {
  4617.             SPrintf(LocalBuffer,WindowName,LocalName);
  4618.  
  4619.             Stream = Open(LocalBuffer,MODE_NEWFILE);
  4620.         }
  4621.         else
  4622.             Stream = Open(WindowName,MODE_NEWFILE);
  4623.     }
  4624.     else
  4625.         Stream = NULL;
  4626.  
  4627.     if(GoodStream(Stream))
  4628.     {
  4629.         ThisProcess -> pr_ConsoleTask = ((struct FileHandle *)BADDR(Stream)) -> fh_Type;
  4630.  
  4631.         OutputStream = Open("*",MODE_NEWFILE);
  4632.     }
  4633.     else
  4634.         OutputStream = NULL;
  4635.  
  4636.     if(Stream && OutputStream)
  4637.     {
  4638.         Result = SystemTags(Command,
  4639.             SYS_Input,    Stream,
  4640.             SYS_Output,    OutputStream,
  4641.             SYS_UserShell,    TRUE,
  4642.         TAG_DONE);
  4643.     }
  4644.     else
  4645.     {
  4646.         Result = SystemTags(Command,
  4647.             SYS_UserShell,    TRUE,
  4648.         TAG_DONE);
  4649.     }
  4650.  
  4651.     if(OutputStream)
  4652.         Close(OutputStream);
  4653.  
  4654.     if(Stream)
  4655.         Close(Stream);
  4656.  
  4657.     ThisProcess -> pr_ConsoleTask = OldConsoleTask;
  4658.  
  4659.     if(OtherName)
  4660.         FreeVecPooled(OtherName);
  4661.  
  4662.     return(Result);
  4663. }
  4664.  
  4665.     /* AskDial(struct Window *Parent):
  4666.      *
  4667.      *    This is called when the user is about to start dialing. If the
  4668.      *    dial button/menu item is available with the protective mode
  4669.      *    enabled, a message will be displayed, asking if the line
  4670.      *    should be hung up before proceeding.
  4671.      */
  4672.  
  4673. BOOL __regargs
  4674. AskDial(struct Window *Parent)
  4675. {
  4676.     if(!DialItemsAvailable)
  4677.     {
  4678.         if(MyEasyRequest(Parent,LocaleString(MSG_CANNOT_DIAL_BECAUSE_TXT),LocaleString(MSG_DIAL_CANCEL_TXT)))
  4679.             FullHangup(TRUE);
  4680.         else
  4681.             return(FALSE);
  4682.     }
  4683.  
  4684.     return(TRUE);
  4685. }
  4686.  
  4687.     /* Strcoll(const STRPTR a1,const STRPTR b1):
  4688.      *
  4689.      *    A working strcoll() like routine, which does string comparison
  4690.      *    ignoring case and accents, but taking special national characters
  4691.      *    into account. I am certain about how the german Umlauts should
  4692.      *    be treated, but the treatment for Æ, Þ, Ð and ÿ is pure guesswork...
  4693.      */
  4694.  
  4695. LONG __regargs
  4696. Strcoll(STRPTR a1,STRPTR b1)
  4697. {
  4698.     enum {    CHAR_any,
  4699.         CHAR_ae,
  4700.         CHAR_oe,
  4701.         CHAR_ue,
  4702.         CHAR_ss,
  4703.         CHAR_ij
  4704.     };
  4705.  
  4706. #ifdef __SASC
  4707. #pragma msg 62 ignore push
  4708. #endif
  4709.  
  4710.     STATIC UBYTE const noaccent[256] =
  4711.     {
  4712.           0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
  4713.          16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
  4714.         ' ','!', 34,'#','$','%','&', 39,'(',')','*','+',',','-','.','/',
  4715.         '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
  4716.         '@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
  4717.         'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',
  4718.         '`','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
  4719.         'P','Q','R','S','T','U','V','W','X','Y','Z','{','|','}','~',127,
  4720.         128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
  4721.         144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
  4722.         ' ','¡','¢','£','¤','¥','¦','§','¨','©','ª','«','¬','­','®','¯',
  4723.         '°','±','²','³','´','µ','¶','·','¸','¹','º','»','¼','½','¾','¿',
  4724.         'A','A','A','A','A','A','A','C','E','E','E','E','I','I','I','I',
  4725.         'D','N','O','O','O','O','O','×','O','U','U','U','U','Y','B','S',
  4726.         'A','A','A','A','A','A','A','C','E','E','E','E','I','I','I','I',
  4727.         'D','N','O','O','O','O','O','×','O','U','U','U','U','Y','B','I'
  4728.     };
  4729.  
  4730. #ifdef __SASC
  4731. #pragma msg 62 pop
  4732. #endif
  4733.  
  4734.     STATIC UBYTE const types[256] =
  4735.     {
  4736.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4737.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4738.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4739.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4740.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4741.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4742.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4743.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4744.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4745.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4746.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4747.         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  4748.         0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,
  4749.         0,0,0,0,0,0,2,0,0,0,0,0,3,0,0,4,
  4750.         0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,
  4751.         0,0,0,0,0,0,2,0,0,0,0,0,3,0,0,5
  4752.     };
  4753.  
  4754.     STRPTR a = (const STRPTR)a1;
  4755.     STRPTR b = (const STRPTR)b1;
  4756.  
  4757.     LONG mul = 1;
  4758.  
  4759. loop:
  4760.  
  4761.     while(*a && *b && noaccent[*a] == noaccent[*b]) { a++; b++; }
  4762.  
  4763.     if(*a || *b)
  4764.     {
  4765.         LONG c = noaccent[*a],d = noaccent[*b];
  4766.  
  4767.         if((types[c] && types[d]) || (!types[c] && !types[d]))
  4768.             return(mul * ((LONG)noaccent[c] - (LONG)noaccent[d]));
  4769.         else
  4770.         {
  4771.             if(types[c] == CHAR_any)
  4772.             {
  4773.                 register STRPTR t;
  4774.                 register LONG e;
  4775.  
  4776.                 e = c;
  4777.                 c = d;
  4778.                 d = e;
  4779.  
  4780.                 t = a;
  4781.                 a = b;
  4782.                 b = t;
  4783.  
  4784.                 mul = -mul;
  4785.             }
  4786.  
  4787.             if(d && noaccent[c] == d)
  4788.             {
  4789.                 switch(types[c])
  4790.                 {
  4791.                     case CHAR_ss:
  4792.  
  4793.                         c = 'S';
  4794.                         break;
  4795.  
  4796.                     case CHAR_ij:
  4797.  
  4798.                         c = 'J';
  4799.                         break;
  4800.  
  4801.                     default:
  4802.  
  4803.                         c = 'E';
  4804.                         break;
  4805.                 }
  4806.  
  4807.                 a++;b++;
  4808.  
  4809.                 d = noaccent[*b];
  4810.  
  4811.                 b++;
  4812.  
  4813.                 if(c == d)
  4814.                     goto loop;
  4815.             }
  4816.  
  4817.             return(mul * ((LONG)noaccent[c] - (LONG)noaccent[d]));
  4818.         }
  4819.     }
  4820.  
  4821.     return(0);
  4822. }
  4823.